標籤:http 使用 width 資料 os 工作
項目裡有一個需求,domain0的應用程式層需要定時給domainU(hvm windows)的應用程式層傳遞一塊資料,原來的方案是在domainU的應用程式層架設一個http伺服器,監聽在某個連接埠,然後需要塞資料時,domain0的應用程式串連該連接埠,並通過http send發送資料。發送完會等待domainU 的應用程式返回一個標記。
無意間看到這篇論文《全虛擬化HVM和半虛擬化PV虛擬平台通訊機制分析》,裡邊介紹hvm情況下domainU與Doamin0使用者層的資料互動機制,根據文章介紹,嘗試設計一種互動方式: 1. domainU 裡增加一個自訂驅動(叫datafront),該驅動對應用程式層提供介面,當應用程式層調用特定系統調用或函數時,datafront觸發vmexit. 該vmexit對應hypervisor_callback會檢測一片共用記憶體區,如果有特定資料就讀取到domainU 應用程式層。2. domain0裡修改應用程式層的 qemu-dm精靈,或者自己寫一個應用程式,當需要塞資料時,將資料寫入共用頁,然後發出事件通知。 大概的過程就是這樣,具體系統後續再考慮。
參考: 這裡
全虛擬化HVM和半虛擬化PV虛擬平台通訊機制分析
一.半虛擬化PV虛擬平台通訊機制
由於基本上所有的裝置驅動都假設自己可以直接存取硬體,同時對硬體擁有完全控制權。但在這虛擬機器系統中是不可能的,一個裝置通常要為多個Guest Domain服務。為了確保管理性和安全訪問,Xen的裝置虛擬化採用了分離式裝置驅動模型。
當Guest Domain是一個準虛擬化的虛擬機器時,虛擬機器的核心是被修改過的,它知道自己不是運行在真實的硬體上。其裝置是由Xen虛擬機器出來的分離裝置模型,要靠Frontend 和Backend協同工作來完成通訊。分離式裝置驅動模型示。
可以看出,前端驅動(Frontend Driver)位於Guest Domain中,負責接收Guest Domain的I/O處理請求,傳遞給後端驅動(Backend Driver),並接受來自後端的處理結果返回給Guest Domain。後端驅動在Domain0中,負責接收來自前端的I/O處理請求,並把請求交給Domain0中的相關驅動來處理,隨後把處理結果返回給Frontend。從而完成Guest Domain的I/O操作。
由於前端和後端位於不同的OS中,它們之間的通訊要依賴共用記憶體環和事件通道來進行。共用環是由前端分配的一塊共用記憶體,在前端和後端間共用。在ring上存在兩對生產者消費者指標。通過共用記憶體環,前端和後端可以把I/O請求放入環中和從環中讀取,而I/O請求的處理結果也可以通過環進行傳遞。事件通道則允許前端和後端發送給對方一個確認資訊。
Xen採用了共用描述符環來實現上述工作,其原理如所示。
Guest Domain把資料轉送的請求放到I/O環上並更新要求生產者指標;Xen取出請求並更新消費者指標。同樣地,當Xen準備好響應資料後,也把一個描述符放到I/O環上並更新應答生產者指標;客戶域取出應答交給應用程式並更新響應消費者指標。
需要注意的是,I/O環上的內容並不是共用資料的內容,而是共用資料所在的緩衝區的描述符,這是因為,對於高速DMA裝置,用描述符是不合適的。真正的資料傳遞是藉助Grant Table完成的。同時,這裡不要求按順序處理請求:
Guest OS給每個請求都建立了唯一的相關標識符,這個標識符會在相關的響應上被複製。描述符環只是限定了能夠處理請求的規模,並不規定處理順序,誰先被處理誰後被處理是在將資料對應到描述符環上的時候決定的,這就允許Xen出於調度和優先順序的考慮,重新排定I/O操作的順序。Xen使用事件通道作為有I/O描述符進入隊列的非同步通知,不管是request請求還是response都可以在同時放入多個描述符項,達到一定的閥值後才發送事件通知。
詳細展示了在Xen虛擬機器系統上,兩個准虛擬化的Guest, Domain1和Domain2之間是如何進行通訊的。當Domain1中的應用程式App1要向Domain2中的應用程式App2發送資料包時,它按照如下的步驟完成:
1. Domain2首先調用send(),將自己使用者空間的資料拷貝到核心空間;
2. Domain2的前端將發送請求放到共用環上,通過更新生產者共用指標完成;
3. 前端將會通過事件通道向Domain0發出一個事件(更新,該事件觸發Back-end去獲得包含了App1資料的頁;back-end讀取請求,獲得頁的物理地址,並發送到響應的Driver;
4. Xen將Domain2的請求移出共用描述符環,並移動請求消費者指標,同時調度Domain1;
5. Domain1中的前端在IO環中用一個指向Grant table中空閑頁的指標填上接收請求;
6. 當back-end接收到資料報時,它首先檢查該資料報屬於誰,然後從IO環中移出接收請求,同時從grant table中擷取空閑頁,然後將空閑頁和資料頁交換,並通過Event channel發出接收事件;
7. 前端通知核心,App2接收資料。
二、Guest Domain是全虛擬化的虛擬機器
當Guest Domian是全虛擬化的虛擬機器時,Xen 為它類比了與真實機器完全一樣的抽象平台,Guest Domain不知道自己運行在Hypervisor上。但是,由於硬體虛擬化技術的引入,例如,在VT-x的CPU上,當虛擬機器控制結構VMCS(Virtual Machine Control Structure)結構體中定義的那些事件被觸發時,就會發生VMExit,從非根狀態切換到根狀態,導致陷入到Hypervisor中,Guest Domain被切換出去。
VMCS結構包含以下6個組成部分:客戶狀態域,主機狀態域,虛擬機器執行控制域,VMExit控制域,VMEntry控制域以及VMExit資訊域。虛擬機器監控器主要通過配置虛擬機器執行控制域來控制虛擬機器在非根環境下的執行行為。通過設定虛擬機器執行控制域,VMM可以對不同VM的VMCS 分別設定不同虛擬機器允出準則,從而實現對不同VM的不同虛擬化策略。
如所示,一個全虛擬化的虛擬機器要想另外一個目標機器發送資料時,其流程如下:
1. Guest Domain中的核心執行In/Out指令觸發VMExit,處理器調用Hypervisor設定的VMExit的處理函數。
2. Hypervisor將I/O指令的具體資訊寫入DomainU的DM共用的一頁I/O共用頁中,並通過事件通道通知Domain0,接著Hypervisor阻塞該虛擬機器,並調用調度演算法。
3. Hypervisor恢複Domain0的狀態,並把執行控制交給Domain0。
4. Domain0中首先被執行的是註冊的回呼函數hypervisor_callback,它再調用evtchn_do_upcall。
5. evtchn_do_upcall裡收集有哪些虛擬機器有多少I/O請求。
6. 執行控制從Xen0的核心態返回使用者程式態。DM本來通過一條select系統調用等待I/O請求,此時得到調度後的DM一旦等到請求到來就返回。
7. 通過讀取I/O共用頁,DM識別是對哪類外設的訪問,調用對應虛擬外設初始化時的回呼函數。
8. 根據不同的請求,虛擬外設的回呼函數或者只是把虛擬外設的狀態寫回I/O共用頁中,或者發生一次真正的資料拷貝。最後DM仍通過事件通道機制通知Hypervisor處理完畢。
9. Hypervisor得到通知後,解除對應的請求I/O的Guest Domain的阻塞。
未來某一時刻,該Guest Domain就可以再次被調度到,繼續運行了。上述整個流程如所示: