qemu-kvm virtio 虛擬化-----Linux客戶機 virtio裝置初始化__Linux

來源:互聯網
上載者:User
Linux客戶機 virtio裝置初始化
virtio裝置物理上串連在pci物理匯流排上,邏輯上串連在virtio虛擬匯流排。做為pci裝置便於資源分派與配置,邏輯裝置模型中,便於管理與組織。
1.qemu-kvm提供的virtio pci裝置
virtio-blk(硬碟),virtio-net(網路),virtio-balloon(氣球)等pci裝置,這些裝置串連在pci匯流排上。代碼位於qemu: hw/virtio-pci.c
static PCIDeviceInfo virtio_info[] = {
    {
        .qdev.name = "virtio-blk-pci",
    },{
        .qdev.name  = "virtio-net-pci",
    },{
        .qdev.name = "virtio-serial-pci",
    },{
        .qdev.name = "virtio-balloon-pci",
       },
}
static void virtio_pci_register_devices(void)
{
    pci_qdev_register_many(virtio_info);


2.客戶機PCI裝置進行枚舉和資源分派
當Linux客戶機系統啟動時,對PCI裝置進行枚舉和資源分派(配置PCI的配置空間),通常由BIOS完成。不過對Linux系統提供方式,一種由BIOS實現,另一種自己實現枚舉和資源分派功能。代碼位於kernel:arch/x86/pci/init.c
static __init int pci_arch_init(void)
{
#ifdef CONFIG_PCI_DIRECT
        int type = 0;

        type = pci_direct_probe();
#endif

#endif
#ifdef CONFIG_PCI_BIOS
        pci_pcbios_init();
#endif
}
真正裝置枚舉和資源分派由這裡開始
static int __init pci_legacy_init(void)
{
        printk("PCI: Probing PCI hardware\n");
        pci_root_bus = pcibios_scan_root(0);
        if (pci_root_bus)
                pci_bus_add_devices(pci_root_bus);

        return 0;
}
pcibios_scan_root()---->pci_scan_bus_parented()---->pci_scan_child_bus()--->pci_scan_slot()--->pci_scan_single_device()----->pci_device_add()
將PCI匯流排上的裝置添加到鏈表
void pci_device_add(struct pci_dev *dev, struct pci_bus *bus)
{
        /*
         * Add the device to our list of discovered devices
         * and the bus list for fixup functions, etc.
         */
        down_write(&pci_bus_sem);
        list_add_tail(&dev->bus_list, &bus->devices);
        up_write(&pci_bus_sem);
}
上述過程執行完成,在/sys/devices/pci0000:00目錄下,建立virtio pci裝置。並且在/sys/bus/pci/devices/目錄下,建立相應對於pci裝置的符號串連,同時在/sys/bus/pci/drivers/目錄下,建立virtio-pci目錄,目錄下存在支援裝置符號串連檔案。

3.virtio匯流排定義與註冊,virtio匯流排為虛擬匯流排,目的為了裝置管理與組織需要。代碼位於:
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,
};

static int virtio_init(void)
{
        if (bus_register(&virtio_bus) != 0)
                panic("virtio bus registration failed");
        return 0;
}   
上述註冊函數調用執行完成,在/sys/bus/目錄下,建立了一個新的目錄virtio,在該目錄下同時建立了兩個檔案夾為devices和drivers。表示建立virtio匯流排,匯流排支援裝置與驅動devices和drivers目錄下。  

4. virtio-pci裝置驅動載入
static struct pci_driver virtio_pci_driver = {
        .name           = "virtio-pci",
        .id_table       = virtio_pci_id_table,
        .probe          = virtio_pci_probe,
        .remove         = virtio_pci_remove,
#ifdef CONFIG_PM
        .suspend        = virtio_pci_suspend,
        .resume         = virtio_pci_resume,
#endif
};
static int __init virtio_pci_init(void)
{
        
        virtio_pci_root = root_device_register("virtio-pci");
        err = pci_register_driver(&virtio_pci_driver);
        return err;
}
上述註冊函數調用執行完成,在/sys/bus/pci/drivers和/sys/devices目錄下建立了virtio-pci檔案夾

5,virtio匯流排子裝置註冊
上面步驟2,對PCI裝置進行枚舉和資源分派中介紹了,枚舉的裝置,已經關聯到匯流排鏈表中。對函數調用pci_register_driver(&virtio_pci_driver)就是對鏈表的每一個pci裝置進行探測,該驅動是否支援該裝置,如果支援進,調用驅動probe函數,完成啟用該pci裝置,同時在virtio匯流排進行註冊裝置。
        bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
        if (drv->probe) {
                ret = drv->probe(dev);
        }

static int __devinit virtio_pci_probe(struct pci_dev *pci_dev,
                                      const struct pci_device_id *id)
{
        struct virtio_pci_device *vp_dev;
        int err;
        
        /* We only own devices >= 0x1000 and <= 0x103f: leave the rest. */
        if (pci_dev->device < 0x1000 || pci_dev->device > 0x103f)
                return -ENODEV;
        
        /* allocate our structure and fill it out */
        vp_dev = kzalloc(sizeof(struct virtio_pci_device), GFP_KERNEL);
        if (vp_dev == NULL)
                return -ENOMEM;

        vp_dev->vdev.dev.parent = virtio_pci_root;
        vp_dev->vdev.dev.release = virtio_pci_release_dev;
        vp_dev->vdev.config = &virtio_pci_config_ops;
        vp_dev->pci_dev = pci_dev;
        INIT_LIST_HEAD(&vp_dev->virtqueues);
        spin_lock_init(&vp_dev->lock);
        /* Disable MSI/MSIX to bring device to a known good state. */
        pci_msi_off(pci_dev);

        /* enable the device */
        err = pci_enable_device(pci_dev);
        if (err)
                goto out;

        err = pci_request_regions(pci_dev, "virtio-pci");
        if (err)
                goto out_enable_device;

        vp_dev->ioaddr = pci_iomap(pci_dev, 0, 0);
        if (vp_dev->ioaddr == NULL)
                goto out_req_regions;

        pci_set_drvdata(pci_dev, vp_dev);

        /* we use the subsystem vendor/device id as the virtio vendor/device
         * id.  this allows us to use the same PCI vendor/device id for all
         * virtio devices and to identify the particular virtio driver by
         * the subsytem ids */
        vp_dev->vdev.id.vendor = pci_dev->subsystem_vendor;
        vp_dev->vdev.id.device = pci_dev->subsystem_device;
        /* finally register the virtio device */
        err = register_virtio_device(&vp_dev->vdev);
        if (err)
                goto out_set_drvdata;

        return 0;

}
上述註冊函數調用執行完成,/sys/devices/virtio-pci/建立相應子裝置{virtio1,virtio2,virtio3},同時在/sys/bus/virtio/devices下面建立三個符號串連檔案{virtio1,virtio2,virtio3}

6. virtio匯流排子裝置驅動註冊。
當virtio匯流排進行註冊裝置register_virtio_device,將調用virtio匯流排的probe函數:virtio_dev_probe()。該函數遍曆驅動,找到支援驅動關聯到該裝置。
   register_virtio_device()--->bus_probe_device()---->device_attach();
   bus_for_each_drv(dev->bus, NULL, dev, __device_attach);
      if (dev->bus->probe) {
                ret = dev->bus->probe(dev);
        } 

static int virtio_dev_probe(struct device *_d)
{       
        int err, i;
        struct virtio_device *dev = container_of(_d,struct virtio_device,dev);
        struct virtio_driver *drv = container_of(dev->dev.driver,
                                                 struct virtio_driver, driver);
        u32 device_features;

        /* We have a driver! */
        add_status(dev, VIRTIO_CONFIG_S_DRIVER);

        /* Figure out what features the device supports. */
        device_features = dev->config->get_features(dev);
        
        /* Features supported by both device and driver into dev->features. */
        memset(dev->features, 0, sizeof(dev->features));
        for (i = 0; i < drv->feature_table_size; i++) {
                unsigned int f = drv->feature_table[i];
                BUG_ON(f >= 32);
                if (device_features & (1 << f))
                        set_bit(f, dev->features);
        }

        /* Transport features always preserved to pass to finalize_features. */
        for (i = VIRTIO_TRANSPORT_F_START; i < VIRTIO_TRANSPORT_F_END; i++)
                if (device_features & (1 << i))
                        set_bit(i, dev->features);

        dev->config->finalize_features(dev);
       err = drv->probe(dev);
        if (err)
                add_status(dev, VIRTIO_CONFIG_S_FAILED);
        else
                add_status(dev, VIRTIO_CONFIG_S_DRIVER_OK);

        return err;
}
//virtio_balloon裝置驅動執行個體
static struct virtio_driver virtio_balloon_driver = {
        .feature_table = features,
        .feature_table_size = ARRAY_SIZE(features),
        .driver.name =  KBUILD_MODNAME,
        .driver.owner = THIS_MODULE,
        .id_table =     id_table,
        .probe =        virtballoon_probe,
        .remove =       __devexit_p(virtballoon_remove),
        .config_changed = virtballoon_changed,
};

static int __init init(void)
{
        return register_virtio_driver(&virtio_balloon_driver);
}      
同時在/sys/bus/virtio/drivers下面建立三個檔案{virtio_balloon,virtio_blk,virtio_console},並且與裝置發生關聯 
//////////////////////////////
熱插拔事件的產生往往是由匯流排驅動級的邏輯處理,所以匯流排一般提供事件發送函數。例如virtio匯流排事件函數virtio_uevent。
static int virtio_uevent(struct device *_dv, st

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.