您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關virtio驅動是如何同設備交互 ,文章內容質量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關知識有一定的了解。
irtio是對虛擬化環境下guest kernel中io操作的一種優化。
首先需要說明的是,在內核的角度來看,virtio設備及其driver,和其他設備及驅動一樣,都是普通的設備,并沒有什么特殊性。也就是說,內核并不知道這種io優化的存在。
virtio設備,在系統層面看,就是pci設備。但是,為了提高io效率,對io操作做出了優化。
主要方案是:
1) 當virtio設備輸出數據時,driver將數據送到buffer隊列中(從virtio網卡驅動的代碼來看,此操作無內存拷貝,直接將數據所占的內存 作為buffer添加到隊列中就完成了),然后通過io指令寫設備寄存器(vp_dev->ioaddr + VIRTIO_PCI_QUEUE_NOTIFY),以通知虛擬機系統(kvm+qemu)。虛擬機系統捕獲了io指令,就得到了通知,從buffer隊 列中獲取設備輸出的數據。
2) 當需要向virtio設備輸入數據時,虛擬機系統將數據送到buffer隊列中,然后觸發設備中斷。driver收到中斷后,直接從隊列中取出數據即可 (從virtio網卡驅動的代碼來看,隊列中的數據已經不需要再進行內存拷貝,隊列中的數據已經是sk_buff結構了)。
從上面的機制來看,virtio并不是完全沒有了io操作。例如,設備輸出數據時,在將數據送入buffer隊列后,還是執行了io操作,以通知虛擬機系統。但是,這個io操作,并不是將輸出數據寫入設備,而是將數據已入隊這件事,寫入設備。
以上是virtio的大體原理。下面來看看virtio的設計思路。
大體分如下4個層次。
一、buffer隊列
既然virtio通過buffer隊列實現設備輸入輸出。那么,如果每一種設備都來實現一下buffer隊列,不是浪費么?沒錯,virtio考慮到這個 共性需求,因此就實現一個共同的buffer隊列模塊——virtio_ring(一個環型隊列)。但是,如果哪天buffer隊列的實現,需要重新設計 怎么辦?考慮到這一點,再對buffer隊列的操作包裝出一個抽象層——struct virtqueue_ops。每一種buffer隊列的實現,只要提供一個virtqueue_ops結構變量給用戶使用即可。這就實現了隊列操作與隊列 實現的解耦。
struct virtqueue_ops
{
int (*add_buf)(struct virtqueue *vq,
struct scatterlist sg[],
unsigned int out_num,
unsigned int in_num,
void *data);
void (*kick)(struct virtqueue *vq);
void *(*get_buf)(struct virtqueue *vq, unsigned int *len);
void (*disable_cb)(struct virtqueue *vq);
bool (*enable_cb)(struct virtqueue *vq);
};
二、pci層
每一個virtio設備(例如:塊設備或網卡),在系統層面看來,都是一個pci設備。這些設備之間,有共性部分,也有差異部分。
1)共性部分:這些設備都需要掛接相應的buffer隊列操作virtqueue_ops,都需要申請若干個buffer隊列,當執行io輸出時,需要向 隊列寫入數據;都需要執行pci_iomap將設備配置寄存器區間映射到內存區間;都需要設置中斷處理;等中斷來了,都需要從隊列讀出數據,并通知虛擬機 系統,數據已入隊。
2) 差異部分:設備中系統中,如何與業務關聯起來。各個設備不相同。例如,網卡在內核中是一個net_device,與協議棧系統關聯起來。同時,向隊列中寫入什么數據,數據的含義如何,各個設備不相同。隊列中來了數據,是什么含義,如何處理,各個設備不相同。
如果每個virtio設備都完整實現自己的功能,又會形成浪費。
針對這個現象,virtio又設計了virtio_pci模塊,以處理所有virtio設備的共性部分。這樣一來,所有的virtio設備,在系統層面看來,都是一個pci設備,其設備驅動都是virtio_pci。
但是,virtio_pci并不能完整的驅動任何一個設備。因此,virtio_pci在probe(接管)每一個設備時,根據每個pci設備的 subsystem vendor/device id來識別出這具體是哪一種virtio設備,然后相應的向內核注冊一個virtio設備。當然,在注冊virtio設備之前,virtio_pci驅動 已經為此設備做了諸多共性的操作。同時,還為設備提供了各種操作的適配接口,例如,一些常用的pci設備操作,還有申請buffer隊列的操作。這些操 作,都通過virtio_config_ops結構變量來適配。
三、virtio驅動
這里講virtio驅動,指的是具體的各個設備的驅動了。例如,網卡或塊設備。有了前面所述的各模塊的工作,virtio各個設備的驅動實現,就相對簡單了。大體來說,除了完成本設備特有的功能以外,剩下的基本就是buffer隊列相關操作了。
那就是申請幾個隊列,并提供相應的回調函數。有數據要輸出,往隊列中送就行了。隊列來數據了,自然會有中斷產生,中斷處理中,自然會觸發回調來處理。
四、virtio_bus
內核中的各種對象,總是有秩序的。為了管理每種具體的virtio驅動及每個具體的virtio設備,干脆搞了一個virtio_bus出來。當然,這個 bus并不存在實際的硬件電路,純粹起個管理與適配作用。就這個管理與適配功能而言,他和pci總線是相似的。全部的virtio driver與virtio device,在virtio_bus中都能夠找到。每當有新的virtio driver或者virtio device注冊到系統中時,系統都會執行一次設備與驅動的匹配操作。
關于virtio驅動是如何同設備交互 就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。