細(xì)說(shuō)Linux虛擬化KVM-Qemu之virtio驅(qū)動(dòng)
說(shuō)明:
KVM版本:5.9.1
QEMU版本:5.0.0
工具:Source Insight 3.5, Visio
1. 概述

前篇文章講完了Qemu中如何來(lái)創(chuàng)建Virtio Device,本文將圍繞Guest OS中的Virtio Driver來(lái)展開(kāi);
看一下Guest OS(Linux)中的Virtio框架高層架構(gòu)圖:

核心模塊為virtio和virtqueue,其他高層的驅(qū)動(dòng)都是基于核心模塊之上構(gòu)建的;
顯然,本文會(huì)延續(xù)這個(gè)系列,繼續(xù)分析virtio-net驅(qū)動(dòng),重心在整體流程和框架上,細(xì)節(jié)不表;
virtio-net,又是一個(gè)virtio設(shè)備,又是一個(gè)PCI設(shè)備,那么驅(qū)動(dòng)會(huì)怎么組織呢?帶著問(wèn)題上路吧。
【文章福利】小編推薦自己的Linux內(nèi)核技術(shù)交流群:【749907784】整理了一些個(gè)人覺(jué)得比較好的學(xué)習(xí)書(shū)籍、視頻資料共享在群文件里面,有需要的可以自行添加哦?。。。ê曨l教程、電子書(shū)、實(shí)戰(zhàn)項(xiàng)目及代碼)? ?


2. 數(shù)據(jù)結(jié)構(gòu)
說(shuō)到驅(qū)動(dòng)怎么能不提linux設(shè)備驅(qū)動(dòng)模型呢,感興趣的朋友可以去看看PCI系列分析文章,簡(jiǎn)單來(lái)說(shuō)就是內(nèi)核創(chuàng)建總線用于掛載設(shè)備,總線負(fù)責(zé)設(shè)備與驅(qū)動(dòng)的匹配。Linux內(nèi)核創(chuàng)建了一個(gè)virtio bus:

virtio設(shè)備和virtio驅(qū)動(dòng),通過(guò)
virtio_device_id
來(lái)匹配,而這個(gè)都是在virtio規(guī)范中定義好的;virtio_device
結(jié)構(gòu)中有一個(gè)struct virtio_config_ops
,函數(shù)集由驅(qū)動(dòng)來(lái)進(jìn)行指定,用于操作具體的設(shè)備;
本文描述的virtio-net驅(qū)動(dòng),既是一個(gè)virtio設(shè)備,也是一個(gè)pci設(shè)備,在內(nèi)核中通過(guò)結(jié)構(gòu)體struct virtio_pci_device
來(lái)組織:

該結(jié)構(gòu)體中維護(hù)了幾個(gè)IO區(qū)域:
Common, ISR, Device, Notify
,用于獲取virtio設(shè)備的各種信息,這個(gè)也是由virtio規(guī)范決定的;通常來(lái)說(shuō)一個(gè)virtio設(shè)備,由以下幾個(gè)部分組成:
Device status field
Feature bits
Notifications
Device Configuration space
One or more virtqueues
從結(jié)構(gòu)體看,它用于充當(dāng)pci設(shè)備和virtio設(shè)備的紐帶,后續(xù)也會(huì)在probe函數(shù)中針對(duì)不同的部分進(jìn)行對(duì)應(yīng)的初始化;
以總線的匹配視角來(lái)看就是這樣子的:

3. 流程分析
3.1 virtio總線創(chuàng)建
先看一下virtio總線的創(chuàng)建,virtio bus當(dāng)然也算是基建了:

bus_register
注冊(cè)virtio總線,總線負(fù)責(zé)匹配,在匹配成功后調(diào)用通用的virtio_dev_probe
函數(shù);千里姻緣一線牽,當(dāng)Virtio的ID號(hào)能對(duì)上時(shí),就會(huì)觸發(fā)驅(qū)動(dòng)探測(cè),所以什么時(shí)候進(jìn)行設(shè)備注冊(cè)呢?
3.2 virtio驅(qū)動(dòng)調(diào)用流程
詳細(xì)的細(xì)節(jié),建議閱讀之前PCI驅(qū)動(dòng)系列的分析文章,下邊羅列關(guān)鍵部分:

virtio-net設(shè)備通過(guò)掛在pci總線上,系統(tǒng)在PCI子系統(tǒng)初始化時(shí)會(huì)去枚舉所有的設(shè)備,并將枚舉的設(shè)備注冊(cè)進(jìn)系統(tǒng);
系統(tǒng)在匹配上之后,調(diào)用設(shè)備的驅(qū)動(dòng);

PCI設(shè)備根據(jù)Vendor ID來(lái)匹配驅(qū)動(dòng);
virtio規(guī)范中規(guī)定基于PCI的virtio設(shè)備,Vendor ID號(hào)為:
0x1AF4
,因此最終調(diào)用的驅(qū)動(dòng)入口為virtio_pci_probe
;

在probe函數(shù)中分配
struct virtio_pci_device
結(jié)構(gòu),前文中也提到過(guò)它負(fù)責(zé)將virtio設(shè)備和pci設(shè)備綁定到一起,最終會(huì)在兩個(gè)設(shè)備驅(qū)動(dòng)的probe函數(shù)中完成整體結(jié)構(gòu)的初始化,也就是virtio_pci_probe
完成一部分,實(shí)際的virtio設(shè)備驅(qū)動(dòng)中完成一部分;virtio_pci_modern_probe
:該函數(shù)的內(nèi)容就與virtio規(guī)范緊密相關(guān)了,簡(jiǎn)單來(lái)說(shuō),virtio設(shè)備都會(huì)按照規(guī)范填充common、device、isr、notification等功能部分,而virtio_pci_modern_probe
函數(shù)通過(guò)virtio_pci_find_capability
去獲取對(duì)應(yīng)的能力,并且通過(guò)map_capability
完成IO空間的映射;virtio_pci_probe
中還設(shè)置了virtio_pci_config_ops
操作函數(shù)集,并傳遞給virtio驅(qū)動(dòng),在驅(qū)動(dòng)中調(diào)用這些回調(diào)函數(shù)來(lái)操作virtio設(shè)備;register_virtio_device
:向系統(tǒng)注冊(cè)virtio設(shè)備,從而也就觸發(fā)了virtio總線的匹配操作,最終調(diào)用virtio_dev_probe
函數(shù);virtio_dev_probe
函數(shù)中按照virtio規(guī)范分階段設(shè)置不同的狀態(tài)、獲取virtio設(shè)備的feature等,并最終調(diào)用實(shí)際設(shè)備的驅(qū)動(dòng)程序了;
原文作者:LoyenWang
