標籤

2009年11月16日 星期一

讀寫SMRAM

http://bbs.pediy.com/showthread.php?t=84835



標 題: 【原創】SMM Rootkit初步 - 讀寫SMRAM(帶你邁入CPU級Rootkit之門)

作 者: 木樁

時 間: 2009-03-29,14:37

鏈 接: http://bbs.pediy.com/showthread.php?t=84835


好吧,我承認標題有點誇大,不介意的都進來BS我把

就像 qihoocom 大俠說的,「SMM XX早就幾萬年前就不是什麼秘密了」,不過國內討論這個的到是鮮見,希望這篇文章能拋磚引玉吧。


之前看到rootkit.com上 Implementing SMM PS/2 Keyboard sniffer 那個代碼,狠狠震撼了一把。於是開始研究SMM,半月下來總算有些收穫。這裡將如何讀寫SMRAM的方法拿出來科普一下,希望更多人能邁入編寫SMM Rootkit的大門。

文章後面提供可以在VPC和VMware兩大虛擬機中運行的代碼,將演示如何在WinXP(SP2)中讀寫SMRAM。(本文只考慮最簡單的系統環境,不涉及 SMM Space Locked(D_LCK)=1 時無法讀寫SMRAM的情況)另外,按 Ivanov 大牛的說法,這種方法侷限性很大,只能在沒有執行 Intel 修補方案的主板上運用(感謝兩大VM模擬的都是I440BX )。


對硬件方面接觸尚淺,文中若有疏漏之處,歡迎指正。



--------------------------------------------------------------------------------------------------------


首先放下PCI相關的諸多知識,我用最短的篇幅敘述讀寫SMRAM的過程。希望這篇文章能帶你邁出SMM Rootkit的第一步。

首先說說什麼是SMM(System Management Mode)。System Management Mode Hack中說:SMM是專門為電源管理設計的執行規則。當進入SMM後,系統的各個部件可以被關閉或者使用最低的功耗。SMM獨立於其他的系統軟件,也可以被用在其他目的...  該文章中文版點這裡


瞭解SMM是什麼東西就夠了,這篇文章不會涉及太多SMM的東西。相反,讀寫SMRAM更需要的是PCI配置空間(PCI Configuration Space)方面的知識。

先講講兩個訪問PCI配置空間的I/O端口:CF8h 和 CFCh

通過向 CF8h 端口寫一個特殊的地址,我們就可以在 CFCh 端口上讀寫指定寄存器的值。這裡要讀的寄存器是位於配置空間偏移為 72h 的8bit寄存器——SMRAM (System Management RAM Control Register)


首先要介紹一下 CF8h 這個I/O端口。實際上 I/O CF8h 寫的是CONFIG_ADDRESS寄存器,所以 CF8h又叫CONFIG_ADDRESS。其佈局如下[1]:

名稱: CONFIG_ADDRESS寄存器結構.gif 查看次數: 1684 文件大小: 7.6 KB

按上圖格式,31位置1(enable),假設I440BX的北橋82443BX位於Bus: 0, Device:0, Func:0(後面將教你如何確定芯片類型以及取得這幾個值),這樣配置空間的基址就是0x80000000。


通過I/O指令向CF8h寫入0x80000000,就可以從 CFCh(CONFIG_DATA)中讀出82443BX配置空間偏移為0的一個DWORD值了。而這個DWORD的高低16位分別是VendorID和DeviceID,如圖:

名稱: PCI配置空間頭部_cut.gif 查看次數: 1675 文件大小: 8.9 KB


下面在我們去讀配置空間偏移為72h的SMRAM前,首先注意一個特性。不知道你注意到沒有,回頭看看CONFIG_ADDRESS的低2位,它們被定義為 0。且不談PCI規範上的大道理,說白了這個地方為0是為了限制你給出的地址——必須為4的整數倍。瞭解到這一點再看那個Register Number 就比較好理解了,原來這個寄存器編號和偏移是這麼對應的。



好了,那麼偏移為72h (01110010) 的SMRAM,最後兩位置零是70h (01110000),即位於編號為1C (11100)的寄存器上。所以只要向 CF8h 裡寫入0x80000070這個地址,此時從 CFCh 端口讀出的數據就是包含SMRAM的一個DWORD了。


名稱: 82443BX Register Map_SMRAM.gif 查看次數: 1686 文件大小: 24.2 KB


假設讀出來的數據為DWORD 380A0000h (00 00 0A 38),對照上面82443BX寄存器表可知:


代碼:

70h    00
71h    00
72h    0A    SMRAM
73h    38    ESMRAMC



好了,SMRAM寄存器讀出來了,下面進入正題:如何將SMRAM內容映射到0xA0000。

從文獻[2]中瞭解到,只要D_OPEN=1時,對物理內存0xA0000的訪問會變成這樣:

名稱: SMRAM_D_OPEN.jpg 查看次數: 1684 文件大小: 23.0 KB


D_OPEN位在哪?SMRAM = 0Ah又代表什麼?根據文獻[1]記載,SMRAM的各位意義如下(關於SMRAM更詳細解釋,見文章末尾補充資料不部分):

代碼:

   7    6      5     4       3      2 - 0
   0  D_OPEN D_CLS D_LCK G_SMRAME C_BASE_SEG
        |                    1       010
        |-> 我們就是要設置 D_OPEN = 1

原來的0Ah就是 0000 1010。只要第四位的D_LCK不為1,好了,向SMRAM寫入4Ah (0100 1010),於是飛躍光明之巔!



附帶程序中整個映射SMRAM過如下:

1. 首先遍歷PCI設備,找到I440BX的82443BX Host Bridge Controller。

    (VMware Workstation 6.0.x中82443BX 的VendorID: 8086h  DeviceID: 7190h)

    (Virtual PC 2007 6.0.x 中82443BX 的VendorID: 8086h  DeviceID: 7192h)

    很幸運,這兩個虛擬機中,82443BX都位於Bus:0, Device:0, Func:0,所以PCI配置空間基址都是0x80000000。

2. 以I/O偽代碼為例,讀SMRAM:

    out( CF8h, 80000070h )   // 還記得0x80000070怎麼來的嗎?

    in( CFCh, eax )          // 讀出包含SMRAM的一個DWORD,如 380A0000h

    shr eax, 10h             // SMRAM的8bit在第三個字節處,右移16位(2字節)

    // 此時AL中就是SMRAM內容了(0Ah)

3. 置D_OPEN為1,並且C_BASE_SEG設為010

    (C_BASE_SEG在初始化時就是010了,不過為了防止意外,最好重設一下)

    out( CF8h, 80000070h )

    mov eax, 384A0000h       // 寫回D_OPEN置1後的SMRAM(4Ah)

    out( CFCh, eax )

4. 此時對物理內存0xA0000-0xBFFFF讀寫,就是在SMRAM中了。寫完試試D_OPEN=0隱藏看看,讀0xA0000是不是又回到顯存了?

注意:當SMM Space Lock(D_LCK)為1時,這種方法是無法修改SMRAM的,只能另闢蹊徑。



另外,關於讀出的SMRAM內容,一定會有人質疑0xA0000處真的是SMRAM?關於這點,可以去看看SMRAM的佈局http://www.sandpile.org/ia32/smm.htm。

我一般是通過7FF0h (EIP) 和7FF4h (EFLAGS) 這兩個DWORD判斷的(SMBASE默認是0xA0000):

> dump [000A7FC0 - 000A8000]

000A7FC0   00 00 00 00 28 00 00 00 00 04 00 00 F0 0F FF FF

000A7FD0   E1 BB 7E 81 83 A0 00 00 B2 00 00 00 00 00 00 00

000A7FE0   20 42 E6 F9 20 42 E6 F9 80 C2 A1 F9 E0 E0 6E 80

000A7FF0   47 8B A1 F9 46 02 00 00 00 90 03 00 31 00 01 80

               EIP       EFLAGS




引用:

補充資料:

這裡是 Intel 440BX AGPset: 82443BX Host Bridge Controller[1] 中關於SMRAM的詳細解釋:

名稱: SMRAM描述-System Management RAM Control Register.gif 查看次數: 1655 文件大小: 16.2 KB

名稱: 內容System Management RAM Control Register.gif 查看次數: 1651 文件大小: 81.5 KB


還有些相關知識,有時間再補上...


參考文獻:

[1] Intel 440BX AGPset: 82443BX Host Bridge Controller

    http://download.intel.com/design/chi...s/29063301.pdf

[2] Shawn Embleton, Sherri Sparks, Cliff Zou.

    SMM Rootkits: A New Breed of OS Independent Malware

[3] Loic Duflot, Daniel Etiemble, Olivier Grumelard.

    Using CPU System Management Mode to Circumvent Operating System Security Functions

[4] Intel 64 and IA-32 Architectures Software Developer's Manual Volume 3B: System Programming Guide

    http://www.intel.com/products/processor/manuals/

[5] A tool for FreeBSD to discover SMRAM on i440BX based motherboards

    http://unix.derkeiler.com/Mailing-Li...att-0448/smm.c



測試環境:

Intel Pentium D 3.0GHz 雙核 + Virtual PC 2007(6.0.192.0) + WinXP(SP2)

Intel Pentium D 3.0GHz 雙核 + VMware Workstation (6.0.4-93057) + WinXP(SP2)

AMD Athlon 64 X2 Dual 4000+ + Virtual PC 2007(6.0.192.0) + WinXP(SP2)


Virtual PC 2007下的運行截圖:

名稱: VPC運行截圖.gif 查看次數: 1684 文件大小: 23.2 KB


由於手頭沒有I440BX的主板,無法使用真實機器測試。另外 AMD64 Architecture Programmer's Manual Volume 2: System Programming 也提及了SMM的相關細節,目前還沒有仔細看。

如果你在其他芯片組上測試成功,歡迎給我來信:upbit@126.com


ps: 忘補上一個開發庫了,程序裡用到了WinIO,可以到這裡http://www.internals.com/

    WinIO這個開發庫附帶C和VB的例子,理論上我這裡給的代碼都能翻譯成C或VB的,有興趣的不妨試試

什麼是SYSTEM MANAGEMENT MODE (SMM)


System Management Mode (SMM) is intended to be used for advanced power-management features and other operating-system-independent functions. The chipset is programmed to recognize many types of events and timeouts. When such an event occurs, the chipset asserts the SMI# input pin. At the next instruction boundary, the microprocessor saves its entire state and enters SMM.

一、概述
只有SMI才會引起進入SMM,處理器保護現場,切換到SMRAM裡的一個獨立位址空間執行SMM代碼,RSM指令會使系統返回到原來的正常模式。SMM相當於實模式,沒有特權級和位址映射,可定址4GB,可執行所有I/O和可用系統指令。
SMI優先順序在所有中斷裡最高。當處於SMM狀態,處理器不識別後繼的SMI請求,但第一個SMI請求可以被鎖存,並在系統退出SMM後被處理。
RSM指令只能在SMM狀態下執行,否則會產生操作符無效異常(exception)。RSMSMRAM裡的處理器內容存回處理器,接著把控制權還給被中斷程式。若處理器在SMRAM中偵測到無效狀態,會shut down並產生一特殊匯流排週期以標識該狀態。
當收到SMI時,若處理器處於HALT狀態,處理器從SMM返回會稍有不同,SMBASE位址也會有所改變。
 
二、SMRAM
SMM時,處理器在SMRAM裡執行代碼和存儲資料,也用其來存儲系統管理資訊(如系統配置和power-down設備的特殊資訊)及OEM SPEC資訊。SMRAM被映射到物理空間,最大是4GB,默認是64KB,開始於物理空間裡的SMBASE(硬體RESET後,預設值是3000H)。
處理器在[SMBASE+8000H]尋找SMI處理程式的第一條指令。[SMBASE+FE00H][SMBASE+FFFFH]存放處理器狀態,即處理器的所有寄存器值。

SMRAM

SMBASE+FFFFH
Start of State Aave Area
SMBASE+FE00H

SMI Handler Entry Point
SMBASE+8000H



SMBASE+8000H
三、SMI執行環境
SMM與實模相似但有所不同,它可以定址4GB,加上E首碼就可以訪問1MB以上空間,DATASTACK可以在4GB的任何地方。
                                      寄存器初始值:
EFLAGS

0000 0002H

EIP

0000 8000H

CS

SMBase(default: 3000h)

DSESFSGSSS

0000H

CR0

Set PEEMTSPG to 0,其他不變

DR7

0400H


四、SMM中的中斷和exception
進入SMM後,所有HW中斷都被禁止(包括可遮罩硬體中斷、單步中斷、中斷點陷阱、NMISMIA20M中斷)。軟體中斷和exception能發生,但建議不要,否則可能會產生不可預料的後果。
NMI會被堵在SMI服務程式入口處,且只有第一個NMI會被鎖存並在退出SMM後被執行。但也可以通過使能INTR引腳並有效INTR的方式來在SMM中使能NMI。在一般情況下,NMI是不可嵌套的,但也有例外。若從NMI處理程式進入SMM,同時有收到新的NMI,就可以在退出SMM後實現嵌套,也就是在老的NMI處理程式裡處理新的NMI
 
五、在SMM裡保存FPU狀態
有時在SMM裡有必要保存FPU狀態,最安全的辦法是先置處理器於保護模式下再存FPU,儘管FSAVE可以以四種格式中任一種來存PFU內容。一般默認是在實模方式下進行,但若在非16位實模下發生SMI就必須進入保護模式執行FSAVEFRSTOR,否則無法正確保存和恢復相關FPU資訊。但存完FPU資訊後,SMI處理程式可以繼續在保護模式下執行,但建議其主要在16/32實模下運行。
 
六、SMM版本識別
31                                                        18 17 16 15                                                                  0
Reserved



SMM版本標識



Bit 17 =1 : SMBASE重定位使能
Bit 16=1 :
支援I/O指令重啟
1
SMBASE
重定位
SMBASE默認是30000H,放在處理器內部的SMBASE寄存器裡,我們可以通過在[SMBASE+FEF8H]處設置SMBASE區來重定位SMRAM。後續SMI請求會在新位址處執行SMI處理程式和存放狀態記憶體(系統重啟後會把SMBASE寄存器又寫成30000H,但INIT不會改變它)。
SMBASE重定位到1MB以上位址,實模下的軟體操作就不能初始化段寄存器到SMBASE
SMBASE可用E首碼來訪問32位元位址大小。
2
I/O
指令重啟
就是允許從SMM狀態返回時從被中斷I/O指令處重新執行。I/O指令重啟區[SMBASE+FF00H]控制I/O指令重啟,值為FFH時允許重啟。但該I/O指令並不是造成SMI的原因。
若從I/O指令進入SMM又收到SMI,處理器會先處理新的SMI再重啟該I/O指令。
 
七、自動HALT重啟
         若處理器在HALT狀態進入SMM,要在[SMBASE+FF02]處置自動HALT重啟標誌位元。SMI處理程式可將它清零或不予理睬,這樣返回時就相應地執行HLT指令後的下一條指令或仍回到HALT狀態。
自動HALT重啟標誌值


進入SMM後的值

退出SMM後標誌值

退出SMM狀態後處理器行為

0

0

1

1

0

1

0

1

返回到被中斷程式或任務的下一條指令
不可預料
返回到HLT指令後的下一條指令
回到HALT狀態

八、多處理器SMM注意事項


MP系統中任一處理器都要能回應SMI


每個處理器都有自己的SMRAM空間。


不同處理器的SMRAM可在同一記憶體空間重疊,但它們的狀態存儲區和動態資料存儲區卻要彼此獨立,代碼和靜態資料可共用。


SMI處理程式要為每個處理器初始化SMBASE


處理器可通過自己的SMI引腳或從APIC介面收到的SMI來響應本地SMIAPIC介面可將SMI分給不同的處理器)。

edge trigger VS level trigger

http://hi.baidu.com/lzzscor/blog/item/b8a8591ccf40198287d6b6ac.html

邊緣觸發是指每當狀態變化時發生一個io事件,條件觸發是只要滿足條件就發生一個io事件。

舉個讀socket的例子,假定經過長時間的沉默後,現在來了100個字 節,這時無論邊緣觸發和條件觸發都會產生一個read ready notification通知應用程序可讀。

應用程序讀了50個字節,然後重新調用api等待io事件。這時條件觸發的api會因為還有50個字節可讀從而立即返回用戶一個read ready notification。而邊緣觸發的api會因為可讀這個狀態沒有發生變化而陷入長期等待。

因此在使用邊緣觸發的api時,要注意每次都要讀到socket返回EWOULDBLOCK為止,否則
這個socket就算廢了。而使用條件觸發的api時,如果應用程序不需要寫就不要關注socket可寫的事件,否則就會無限次的立即返回一個write ready notification。

大家常用的select就是屬於條件觸發這一類,以前本人就犯過長期關注socket寫事件從而
CPU 100%的毛病。

恩,最近用poll也碰到了這個問題,呵呵。

ACPI VS APIC

http://mlsx.xplore.cn/2006/01/12/what-difference-between-acpi-and-apic.html

很多人問道了什麼ACPI,什麼是APIC,他們有沒有關係?名字這麼相近。下面給出我對其的一些理解,具體的解釋可以查看內核文檔庫的內核參數文件:
/usr/src/`uname -r`/Documents/kernel-parameters.txt
ACPI
ACPI就是Advanced Configuration and Power Interface的縮寫,意思是「高級配置與電源接口」。這是英特爾、微軟和TOSHIBA共同開發的一種電源管理標準。
ACPI可實現以下功能:   
  1. 用戶可以使外設在指定時間開關;   
  2. 使用筆記本電腦的用戶可以指定計算機在低電壓的情況下進入低功耗狀態,以保證重要的應用程序運行;   
  3. 操作系統可以在應用程序對時間要求不高的情況下降低時鐘頻率;
  4. 操作系統可以根據外設和主板的具體需求為它分配能源;
  5. 在無人使用計算機時可以使計算機進入休眠狀態,但保證一些通信設備打開;
  6. 即插即用設備在插入時能夠由ACPI來控制。
不過,ACPI和其他的電源管理方式一樣,要想享受到上面這些功能,必須要有軟件和硬件的支援。在軟件方面,Windows 98及其後續產品和Windows 2000都對ACPI給予了全面的支援;而Linux的內核目前對此支援得並不是太理想。硬件方面比較麻煩,除了要求主板、顯卡和網卡等外設要支援 ACPI外,還需要機箱電源的配合。電源在提供5伏電壓給主板的同時,還必須使電流穩定在720毫安以上才可以,這樣它才能夠實現電腦的「睡眠」和「喚醒」。

ACPI共有六種狀態,分別是S0到S5,它們代表的含義分別是:
  • S0–實際上這就是我們平常的工作狀態,所有設備全開,功耗一般會超過80W;
  • S1–也稱為POS(Power on Suspend),這時除了通過CPU時鐘控制器將CPU關閉之外,其他的部件仍然正常工作,這時的功耗一般在30W以下;(其實有些CPU降溫軟件就是利用這種工作原理)
  • S2–這時CPU處於停止運作狀態,總線時鐘也被關閉,但其餘的設備仍然運轉;
  • S3–這就是我們熟悉的STR(Suspend to RAM),這時的功耗不超過10W;
  • S4–也稱為STD(Suspend to Disk),這時系統主電源關閉,但是硬盤仍然帶電並可以被喚醒;
  • S5–這種狀態是最乾脆的,就是連電源在內的所有設備全部關閉,功耗為0。
我們最常用到的是S3狀態,即Suspend to RAM(掛起到RAM)狀態,簡稱STR。顧名思義,STR就是把系統進入STR前的工作狀態數據都存放到RAM中去。

在STR狀態下,電源仍然繼續為記憶體等最必要的設備供電,以確保數據不丟失,而其他設備均處於關閉狀態,系統的耗電量極低。一旦我們按下Power按鈕(主機電源開關),系統就被喚醒,馬上從RAM中讀取數據並恢復到STR之前的工作狀態。RAM的讀寫速度極快,因此我們感到進入和離開STR狀態所花費的時間不過是幾秒鐘而已;

而S4狀態,即 STD(掛起到HDD)與STR的原理是完全一樣的,只不過數據是保存在硬盤中。由於硬盤的讀寫速度比RAM要慢得多,因此用起來也就沒有STR那麼快了。 STD的優點是只通過軟件就能實現,比如Windows 2000就能在不支援STR的硬件上實現STD。
之前的電源管理是APM(Advanced Power Management),那麼ACPI和APM相比有什麼區別呢?

ACPI與APM比較
  • APM 1.0&1.1:由BIOS執行電源管理;
  • APM 1.2:操作系統定義電源管理時間,由BIOS負責執行;
  • ACPI:BIOS收集硬件信息,定義電源管理方案;由操作系統負責執行。
  • APM是一種軟件解決方案,因此是與操作系統有關的, 而ACPI是工業標準,包括了軟件和硬件方面的規範。
APIC
APIC(高級可編程中斷控制器)對計算機來講有兩個作用,
  1. 管理IRQ的分配,可以把傳統的16個IRQ擴展到24個(傳統的管理方式叫PIC),以適應更多的設備。
  2. 管理多CPU。由於Nf2主板並不支援多CPU,所以,APIC關閉直接的影響是減少了可用的IRQ。
不過,如果板卡不是非常多的話,關閉 APIC對系統是沒有什麼影響的。
要實現SMP功能,我們使用的CPU必須具備以下要求:
CPU 內部必須內置APIC單元。Intel 多處理規範的核心就是高級可編程中斷控制器(Advanced Programmable Interrupt Controllers–APICs)的使用。CPU通過彼此發送中斷來完成它們之間的通信。通過給中斷附加動作(actions),不同的CPU可以在某種程度上彼此進行控制。每個CPU有自己的APIC(成為那個CPU的本地APIC),並且還有一個I/O APIC來處理由I/O設備引起的中斷,這個I/O APIC是安裝在主板上的,但每個CPU上的APIC則不可或缺,否則將無法處理多CPU之間的中斷協調。
APIC可能遇到的問題,很多這類問題可以通過BIOS更新來解決。

下面的是通過更改HAL類型來解決

CPU實際運行頻率與BIOS設定頻率不符
NF2的用戶大約有10%的會出現CPU實際運行頻率與BIOS設定頻率不符的問題。我們稱之為「頻率不對」。這種現象帶來的直接後果就是在測試3dmark或跑3D遊戲的時候,會感覺不流暢,也稱之為「頓」。
一般在更改BIOS設置後、更新驅動後重啟時,用測試軟件如Aida32、MBM5等可以看到CPU的運行頻率和你在BIOS裡設置得不一樣,而且差距很大。這個時候,用super pi測試CPU速度,會比平常花費時間長好幾秒,用3dmark跑測試,會比平常低幾百分甚至上千分。在3dmark中看到的CPU頻率,也與BIOS設定不符合。如果出現這種情況,則屬於我們所討論的「頻率不對」的問題。
不過,不是所有的3D遊戲「頓」都是這個原因。判斷的方法是:如果你只有個別遊戲「頓」,或者用上述軟件測試頻率正確,就不是此問題。
如果判斷確實屬此問題,解決的方法也很簡單,經過網友討論,只要關閉APIC功能即可。(注意,是APIC,不是ACPI)。

有一些服務器(比如IBM的,HP的),安裝LINUX時,會給出內核的錯誤,導致無法安裝,這個時候可以在安裝的時候輸入
linux acpi=off noapic
應該是安裝上的。

轉載請註明: 轉載自Linux|系統管理|WEB開發

2009年11月4日 星期三

Intel VMX

轉自:
http://pengsunshine.blogspot.com/2008/03/intel-vmx.html

Intel提供了處理器級的VMX(Virtual-Machine Extensions),從硬件層面支持VT技術。本文及後續的幾篇文章將結合"Intel 64 and IA-32 Architectures Software developer's Manual (Volume 3B)"和自己使用Xen的經驗寫些東西,算是學習筆記吧,不足之處在所難免,哪位看到了希望能共同交流提高 (^_^)。

先看一下虛擬機的體系結構:Intel VMX的體系結構可劃分為兩層:VMM和VM。

  • VMM(Virtual-Machine Monitors)作為host,具有對processor(s)和平台硬件的完全控制權限。它為guest提供VCPU(virtual processor)的抽象,並允許guest直接運行在邏輯處理器(logical processor)上。VMM具有對處理器資源、物理內存、中斷和IO的選擇控制的權利。(舉例:Xen就是一種VMM。)
  • VM(Virtual-Machine)相應地作為guest,其實是提供了一種guest軟件環境:它維護一個棧,其中包含了OS和application software。其每個操作都獨立於其他的VM,並且使用由同一個物理平台所提供的對處理器、內存、硬盤、顯卡、IO訪問的統一接口。此外,這個棧並不知道VMM的存在。運行於VM中的軟件其權限是受限的,這樣才能保障VMM對整個平台資源的完全控制。(舉相應的例子:Xen上跑的Guest OS就是VM。)


下面來簡要介紹一下VMX operation。支持虛擬化的處理器其虛擬化相關的操作被稱為VMX operation 。它分為兩類:VMX root operation 和 VMX non-root operation 。通常來說,VMM 運行於 VMX root operation 而 guest 運行於 VMX non-root operation 。兩種operation之間的轉換被稱為VMX transitions:從root到non-root被稱為VM entries,而從non-root到root則稱為VM exits。簡單可如下圖所示:




處於VMX root operation的CPU其行為與在VMX operation之外是基本一樣的,最根本的不同之處在於其增加了一套新的VMX指令集,且能存儲到特定控制寄存器的值是有限的。而處於VMX non-root operation的CPU起行為是受限的,且經過了修改以幫助實現virtualization。與其普通的operation不同,特定的指令(包括新增的VMCALL指令)和事件將導致VM exits從而進入VMM:由於這些VM exits代替了以前正常的行為,所以在VMX non-root operation中的軟件的功能是受限的(也正是這種限制保證了VMM能夠始終具有控制處理器資源的能力)。

從 guest的角度,沒有任何一個Guest可見的位來指示一個邏輯處理器是否處於VMX non-root operation,這樣VMX就能保證guest並不知道其正在運行於一個VM中。即便是CPL(current privilege level)為0,VMX operation也給guest加了限制,這樣guest software就可以完全不必改變其原始的設計,這也簡化了VMM的開發。

現在就可以看一下VMM與Guest之間的交互了。大體的流程是這樣子的:



  1. oftware執行VMXON指令進入VMX operation
  2. 通過VM entries,VMM就可以進入VM的guest中(VMM通過VMLANCH和VMRESUME來觸發VM entry,並通過VM exits重新獲得控制權)
  3. VM exits將控制權轉移到由VMM定義的entry point(VMM可以採取適當的動作來觸發VM exit,然後再使用一個VM entry就可以返回到VM中)。
  4. 最後,VMM通過VMXOFF指令關閉自身並退出VMX operation

既然已經涉及到VMX指令,下面又引出一個非常重要的數據結構VMCS(Virtual-Machine Control Structure),這個數據結構在下文中還要非常詳細地介紹。對VMCS的訪問是由一組被稱作VMCS pointer(每個logical processor有一個VMCS pointer)的處理器狀態來管理的。VMCS pointer是一個64位的VMCS地址,可通過VMPTRST和VMPTRLD指令對其進行讀寫;VMM可以使用VMREAD、VMWRITE、 VMCLEAR指令對VMCS進行配置。對VMM所管理的每個VM,VMM可以使用不同的VMCS;且對VM中的每個logical processor(or vcpu),VMM也可以為每個vcpu使用不同的VMCS。

VMX operation需要處理器支持,那麼如何從軟件層面斷定一個處理器是否支持VMX operation:通過CPUID --- 如果CPUID.1:ECX.VMX[bit 5] = 1,那說明該CPU支持VMX operation。現有的VMX體系結構的設計具有良好的可擴展性,software可以使用一個VMX capability MSRs集來獲得VMX新增的擴展特性。

現在再來看看如何使能和進入VMX operation:進入VMX operation之前,system software通過設置CR4.VMXE[bit 13] = 1 來使能VMX,之後就可以通過VMXON指令來進入VMX operation。如果CR4.VMXE = 0,VMXON將導致一個invalid-opcode異常(#UD),而且一旦進入VMX operation,CR4.VMXE就無法在此中被清零;system software通過VMXOFF離開VMX operation,只有在VMX operation外部CR4.VMXE才能被清零。

VMXON由IA32_FEATURE_CONTROL MSR (MSR address 3AH)所控制,當一個logical processor被rest時,該MSR被清零。此MSR的相關位如下:

  • Bit 0 is the lock bit. 若該位被清零,VMXON就會觸發一個general-protection exception;若該位被置1,向此MSR進行WRMSR也會觸發general-protection exception,直到a power up reset condition發生時該MSR才能被修改。系統BIOS可以通過該比特位來禁用VMX,若要打開VMX支持,BIOS必須設置該MSR的bit 0, bit 1, bit 2。
  • Bit 1 enables VMXON in SMX operation. 若該位被清零,SMX operation中的VMXON將觸發一個general-protection exception。若在不同時支持VMX和SMX的logical processors上試圖設置該位,將會觸發general-protection exceptions。(若一個logical processor自從最後一次執行GETSEC[SENTER]為止GETSEC[SEXIT]還未被執行,則稱其in SMX operation)
  • * Bit 2 enables VMXON outside SMX operation. 若該位被清零,在SMX operation外部進行VMXON將觸發一個general-protection exception。在不支持VMX的logical processors上試圖設置該位將觸發general-protection exceptions。(若一個logical processor還未執行GETSEC[SENTER]或最後一次執行過GETSEC[SENTER]後又執行了GETSEC[SEXIT],則稱其 outside SMX operation)

在執行VMXON之前,software應該分配出(保留)一塊4KB對齊的內存區域供logical processor用以支持VMX operation。這個內存區域就被稱為VMXON region。

最後,簡單說說VMX operation上的限制:VMX operation對processor operation作了一些限制,諸如:
  • 在VMX operation中,處理器將對CR0和CR4的某些具體位填充固定值(CR0.PE, CR0.NE, CR0.PG, cR4.VMXE的值都必須為1)。如果這些位中任何一位的值並不是它應該的值,VMXON就會fail。在VMX operation中任何試圖使用CLTS, LMSW, MOV CR等指令改變這些位的值都將導致general-protection exception。VM entry或VM exit都無法將這些位的值設置為其不應該的值。(CR0.PE和CR0.PG的限制就說明了VMX operation必須處於paged protected mode,這也使得guest software無法運行於unpaged protected mode或real-address mode中)
  • 若logical processor處於A20M mode,VMXON會fail。一旦處理器進入VMX operation, A20M的中斷就會被block,這樣VMX operation中A20M mode當然是不可能的了。
  • 只要logical processor處於VMX root operation,INIT signal就會被block;在VMX non-root operation中它是不會被block的,此時INITs將觸發VM exits。

從源碼級別,Xen裡面的vmx.c描述的就是Intel VMX體系結構相關的VM Exits支持:對照著Intel的Manual可以找到Xen對其的具體實現。