精品国产人成在线_亚洲高清无码在线观看_国产在线视频国产永久2021_国产AV综合第一页一个的一区免费影院黑人_最近中文字幕MV高清在线视频

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

linux設備中virtio組織關系及設備初始化調用流程

454398 ? 來源: Chinaunix ? 作者:lvyilong316 ? 2020-09-25 15:47 ? 次閱讀

我們看linux kernel中virtio驅動相關代碼,會發現有很多相關文件。首先有virtio.c這種文件,其次還有virtio_pci.c,virtio_scsi.c等這些文件,還有virtio_net.c,virtio_blk.c,virtio_balloon.c等這些。那么這些文件是什么關系呢?其次里面很多還有各自probe函數,到底是如何調用的,例如以網絡的virtio_net到底是從哪里開始初始化的?要理清這些關系需要以linux設備驅動模型為背景展開討論。這篇文章,我們以linux kernel 3.10代碼為例,分析一下virtio的相關組織關系,以及設備初始化調用流程。

總線及驅動的注冊

linux設備驅動模型的核心有三個概念:設備(device),驅動(driver),總線(bus)。而如果我們把virtio的相關關系梳理清楚后,以網絡virtio_net為例映射到設備驅動模型,就得到了下圖。我們這個小節后面就以下圖為背景展開。

圖1

linux將virtio實現分離成兩部分:和物理總線標準相關的(如pci,scsi等),和物理總線標準無關的。

圖中左側部分即和物理總線相關的實現,這里以pci為了,當然virtio也支持其他總線類型,如scsi。virtio-pci是virtio對應pci的驅動實現,所以virtio-pci是一個pci總線上的一個驅動。它通過如下方式注冊到pci總線上去。

lvirtio總線的注冊

點擊(此處)折疊或打開

/*virtio.c*/

static struct bus_type virtio_bus={

.name="virtio",

.match=virtio_dev_match,

.dev_attrs=virtio_dev_attrs,

.uevent=virtio_uevent,

.probe=virtio_dev_probe,

.remove=virtio_dev_remove,

};

staticintvirtio_init(void)

{

if(bus_register(&virtio_bus)!=0)

panic("virtio bus registration failed");

return 0;

}

core_initcall(virtio_init);

如代碼所示,這個總線的名字叫”virtio”,通過bus_register就將virtio總線注冊進系統,可以在sys文件系統中查看。

lvirtio-net驅動注冊

最后我們看我們經常接觸到設備驅動的初始化,我們以網絡驅動virtio_net為例,其對應的驅動為virtio-net。其注冊過程如下。

點擊(此處)折疊或打開

/*virtio-net.c*/

static struct virtio_device_id id_table[]={

{VIRTIO_ID_NET,VIRTIO_DEV_ANY_ID},

{0},

};

static struct virtio_driver virtio_net_driver={

.feature_table=features,

.feature_table_size=ARRAY_SIZE(features),

.driver.name=KBUILD_MODNAME,

.driver.owner=THIS_MODULE,

.id_table=id_table,

.probe=virtnet_probe,

.remove=virtnet_remove,

.config_changed=virtnet_config_changed,

#ifdef CONFIG_PM

.freeze=virtnet_freeze,

.restore=virtnet_restore,

#endif

};

module_virtio_driver(virtio_net_driver);

#define module_virtio_driver(__virtio_driver)\

module_driver(__virtio_driver,register_virtio_driver,\

unregister_virtio_driver)

intregister_virtio_driver(struct virtio_driver*driver)

{

/*Catch this early.*/

BUG_ON(driver->feature_table_size&&!driver->feature_table);

driver->driver.bus=&virtio_bus;

return driver_register(&driver->driver);

}

最終通過register_virtio_driver函數將驅動的bus設置為之前注冊的virtio總線,完成總線的注冊。這樣我們就能在sys文件系統對應virtio總線下的drivers目錄看到這個驅動了。

所以我們再回頭來看圖1,可以看到virtio設備是橫跨兩類總線及驅動的。

virtio設備的初始化流程

梳理清楚virtio相關設備,總線及驅動關系后我們看下virtio設備的初始化過程,我們還是以網絡virtio_net設備為例子。這個初始化過程如下圖2中的黃色部分所示。

圖2

首先是系統啟動kernel初始化階段,pci子系統調用pci_scan_device發現pci網卡設備,并初始化對應pci_dev結構,然后將去注冊到pci總線上(dev->dev.bus=&pci_bus_type)。同時設置devicevendor_id0x1AF4virtiopci vendor_id,device_id為1

然后當我們加載virtio-pci驅動時,當調用module_pci_driver(virtio_pci_driver)將virtio-pci驅動注冊在pci總線上時,在linux設備驅動模型中,這會導致對pci總線設備鏈表上未被驅動綁定的每個設備調用pci總線的match回調函數,即pci_bus_match函數。原型如下:

static int pci_bus_match(struct device *dev, struct device_driver *drv)

pci_bus_match函數將linux設備驅動模型核心出入的device結構轉換為pci_dev結構,將device_driver結構轉換為pci_driver結構,之后調用pci_match_device函數判斷pci設備結構是否有匹配的pci設備ID結構。如果有則判斷設備的pci ID和驅動設置的id_table中是否一樣,如果一樣說明設備和驅動匹配(這里設備的vendor_id和virtio-pci的virtio_pci_id_table匹配),將struct device的driver指針指向驅動,然后調用pci總線的probe函數,即pci_deivce_probe函數。這個函數再次將struct device強制轉換成struct pci_dev,將設置在設備中的driver結構強制轉換為struct pci_derver。它再次校驗這個驅動能否支持這個設備,遞增設備的引用計數,然后調用pci驅動probe函數(即virtio-pci的probe函數virtio_pci_probe),傳入它應該綁定到的struct pci_dev結構體指針。這就進入到了圖2中黃色部分的函數調用鏈了。

在開始梳理virtio_net初始化調用鏈前我們先看其對應的結構struct virtio_pci_device,將其展開得到圖3。

圖3

我們看到virtio_pci_device可以分為兩部分,一部分是和pci總線相關的設備對應struct pci_dev,另一部分是和virtio總線相關的設備對應structvirtio_device。

virtio_pci_probe函數主要負責完成pci_dev部分的初始化,已經virtio_device部分初始化,然后調用register_virtio_device函數。

register_virtio_device函數將virtio_device的設備總線設置為virtio總線,然后調用device_register將virtio_device對應的設備添加到virtio總線上。這個添加總線的動作,會觸發virtio總線的match函數即virtio_dev_match調用,同樣該函數會比較設備dev的pci id和驅動id (virtio net的devid為1),如果匹配則virtio bus的probe函數virtio_dev_probe將被調用。其中又會調用對應驅動的probe函數,即virtnet_probe。而virtnet_probe將會完成virtio net設備structvirtio_device剩余部分的初始化。

到此,virtio net的初始化流程就已經梳理清楚了。virtio net設備創建完成后也會分別出現在pci總線和virtio總線的drvices目錄下。

最后附上virtio的其他類型設備id:

點擊(此處)折疊或打開

#define VIRTIO_ID_NET1/*virtio net*/

#define VIRTIO_ID_BLOCK2/*virtio block*/

#define VIRTIO_ID_CONSOLE3/*virtio console*/

#define VIRTIO_ID_RNG4/*virtio rng*/

#define VIRTIO_ID_BALLOON5/*virtio balloon*/

#define VIRTIO_ID_RPMSG7/*virtio remote processor messaging*/

#define VIRTIO_ID_SCSI8/*virtio scsi*/

#define VIRTIO_ID_9P9/*9p virtio console*/

#define VIRTIO_ID_RPROC_SERIAL 11/*virtio remoteproc seriallink*/

#define VIRTIO_ID_CAIF 12/*Virtio caif*/

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • Linux
    +關注

    關注

    87

    文章

    11232

    瀏覽量

    208957
  • 總線
    +關注

    關注

    10

    文章

    2869

    瀏覽量

    87995
  • 設備驅動
    +關注

    關注

    0

    文章

    68

    瀏覽量

    10879
收藏 人收藏

    評論

    相關推薦

    【明天會更好】關于應屆畢業生檔案、戶口、party組織關系...

    關于應屆畢業生檔案、戶口、party組織關系的問題:作為過來人,我覺得應屆畢業生檔案、戶口、party組織關系等這些問題必須得自己搞清楚了。不然有你吃虧的一天呀!{:soso_e116:}
    發表于 05-14 16:52

    c語言編程多個文件的組織關系錯誤

    c語言編程多個文件的組織關系錯誤 因為keyboard.c,display.c需要reg52.h,為皮面重定義我建了reg.h中有:#include 已知:main.c: #include
    發表于 06-15 14:51

    如何初始化函數? 如何從代碼配置器調用函數?

    :V3.30XC8:V1.37 OS:Mac OS 1011區域:如何初始化函數和調用函數?設備:PIC16F1847外圍設備:EASART,ADCMOD:異步
    發表于 10-15 09:38

    處理器和PCH設備之間的通訊流程是怎樣的?

    QAT相關的名詞組織關系是什么?處理器和PCH設備之間的通訊流程是怎樣的?服務實例與硬件是如何交互的?
    發表于 07-23 08:12

    StratoVirt 的 virtio-blk 設備是如何實現的?

    virtio-blk 設備支持一個隊列:request_queue。該隊列負責 block 設備初始化以及 IO 命令傳輸。StratoVirt 為該隊列配置了對應的 event_
    發表于 06-29 10:37

    LINUX系統引導和初始化-LINUX內核解讀

    Linux 的系統引導和初始化 ----------Linux2.4.22內核解讀之一 一、 系統引導和初始化概述 相關代碼(引導扇區的程序及其輔助程序,以 x86體系為例): \
    發表于 11-03 22:31 ?53次下載

    objc源碼NSObject如何進行初始化

    + alloc 和 - init 這一對我們在 iOS 開發每天都要用到的初始化方法一直困擾著我, 于是筆者仔細研究了一下 objc 源碼 NSObject 如何進行初始化。 在具
    發表于 09-26 09:58 ?0次下載

    Linux內存初始化

    之前有幾篇博客詳細介紹了Xen的內存初始化,確實感覺這部分內容蠻復雜的。這兩天在看Linux內核啟動內存的初始化,也是看的云里霧里的,想嘗試下邊看邊寫,在寫博客的過程
    發表于 10-12 11:16 ?0次下載

    Linux內核初始化過程調用順序

    所有的__init函數在區段.initcall.init還保存了一份函數指針,在初始化時內核會通過這些函數指針調用這些__init函數指針,并在整個初始化完成后,釋放整個init區段
    發表于 05-12 08:40 ?1605次閱讀

    uboot中進行LCD初始化流程免費下載

    本文檔的主要內容詳細介紹的是uboot中進行LCD初始化流程免費下載。
    發表于 08-12 08:00 ?11次下載
    uboot中進行LCD<b class='flag-5'>初始化</b>的<b class='flag-5'>流程</b>免費下載

    UCOS2系統內核講述(二)_ 初始化調用函數

    UCOS2系統內核講述(二)_初始化調用函數
    的頭像 發表于 03-25 09:57 ?1744次閱讀
    UCOS2系統內核講述(二)_ <b class='flag-5'>初始化</b><b class='flag-5'>調用</b>函數

    EE-359:ADSP-CM40x引導時間優化和設備初始化

    EE-359:ADSP-CM40x引導時間優化和設備初始化
    發表于 05-21 09:39 ?10次下載
    EE-359:ADSP-CM40x引導時間優化和<b class='flag-5'>設備</b><b class='flag-5'>初始化</b>

    eMMC初始化命令發送流程

    eMMC初始化命令發送流程通過stm32單片機驅動eMMC芯片,在完成項目的過程,命令發送和響應很令人頭疼,所以整理出一篇文檔供各位開發者參考。初始化命令發送
    發表于 12-05 19:21 ?18次下載
    eMMC<b class='flag-5'>初始化</b>命令發送<b class='flag-5'>流程</b>

    Linux終端初始化和tty驅動框架

    initcall機制 注意上述流程,我們來理解一下 initcall 機制: 普通我們寫一個程序,想要它被調用,需要在主流程調用這個函數,
    的頭像 發表于 09-28 16:33 ?667次閱讀
    <b class='flag-5'>Linux</b>終端<b class='flag-5'>初始化</b>和tty驅動框架

    OP-TEE的內核初始化函數調用

    generic_boot_init_primary函數內容 generic_boot_init_primary函數是OP-TEE建立系統運行環境的入口函數,該函數會進行建立線程運行空間、初始化
    的頭像 發表于 11-02 18:18 ?721次閱讀
    OP-TEE的內核<b class='flag-5'>初始化</b>函數<b class='flag-5'>調用</b>