国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

QEMU源碼全解析 —— PCI設(shè)備模擬(7)

這篇具有很好參考價(jià)值的文章主要介紹了QEMU源碼全解析 —— PCI設(shè)備模擬(7)。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

接前一篇文章:

上一回講解了pci_edu_realize函數(shù)中的pci_register_bar函數(shù),本回開(kāi)始對(duì)于edu設(shè)備的MMIO讀寫函數(shù)進(jìn)行解析。

操作系統(tǒng)與PCI設(shè)備交互的主要方式是PIO和MMIO。MMIO雖然是一段內(nèi)存,但是其沒(méi)有EPT映射,在虛擬機(jī)訪問(wèn)設(shè)備的MMIO時(shí),會(huì)產(chǎn)生VM Exit;KVM識(shí)別此MMIO訪問(wèn)并且將該訪問(wèn)分派到應(yīng)用層QEMU中;QEMU根據(jù)內(nèi)存虛擬化的步驟進(jìn)行分派,找到設(shè)備注冊(cè)的MMIO讀寫回調(diào)函數(shù);設(shè)備的MMIO讀寫回調(diào)函數(shù)根據(jù)設(shè)備的功能進(jìn)行模擬,完成模擬之后可能會(huì)發(fā)送中斷到虛擬機(jī)中,從而完成一些MMIO訪問(wèn)。

前文書(QEMU源碼全解析 —— PCI設(shè)備模擬(5))已經(jīng)講過(guò),pci_edu_realize函數(shù)中調(diào)用memory_region_init_io函數(shù),指定其讀寫函數(shù)是edu_mmio_ops。

QEMU源碼全解析 —— PCI設(shè)備模擬(7),QEMU,KVM,QEMU,KVM,PCI

edu_mmio_ops在hw/misc/edu中初始化,代碼如下:

static const MemoryRegionOps edu_mmio_ops = {
    .read = edu_mmio_read,
    .write = edu_mmio_write,
    .endianness = DEVICE_NATIVE_ENDIAN,
    .valid = {
        .min_access_size = 4,
        .max_access_size = 8,
    },
    .impl = {
        .min_access_size = 4,
        .max_access_size = 8,
    },

};

edu_mmio_ops的類型為MemoryRegionOps,此結(jié)構(gòu)在include/exec/memory.h中定義,代碼如下:

typedef struct MemoryRegionOps MemoryRegionOps;

而struct MemoryRegionOps的定義也在include/exec/memory.h中,如下:

/*
 * Memory region callbacks
 */
struct MemoryRegionOps {
    /* Read from the memory region. @addr is relative to @mr; @size is
     * in bytes. */
    uint64_t (*read)(void *opaque,
                     hwaddr addr,
                     unsigned size);
    /* Write to the memory region. @addr is relative to @mr; @size is
     * in bytes. */
    void (*write)(void *opaque,
                  hwaddr addr,
                  uint64_t data,
                  unsigned size);

    MemTxResult (*read_with_attrs)(void *opaque,
                                   hwaddr addr,
                                   uint64_t *data,
                                   unsigned size,
                                   MemTxAttrs attrs);
    MemTxResult (*write_with_attrs)(void *opaque,
                                    hwaddr addr,
                                    uint64_t data,
                                    unsigned size,
                                    MemTxAttrs attrs);

    enum device_endian endianness;
    /* Guest-visible constraints: */
    struct {
        /* If nonzero, specify bounds on access sizes beyond which a machine
         * check is thrown.
         */
        unsigned min_access_size;
        unsigned max_access_size;
        /* If true, unaligned accesses are supported.  Otherwise unaligned
         * accesses throw machine checks.
         */
         bool unaligned;
        /*
         * If present, and returns #false, the transaction is not accepted
         * by the device (and results in machine dependent behaviour such
         * as a machine check exception).
         */
        bool (*accepts)(void *opaque, hwaddr addr,
                        unsigned size, bool is_write,
                        MemTxAttrs attrs);
    } valid;
    /* Internal implementation constraints: */
    struct {
        /* If nonzero, specifies the minimum size implemented.  Smaller sizes
         * will be rounded upwards and a partial result will be returned.
         */
        unsigned min_access_size;
        /* If nonzero, specifies the maximum size implemented.  Larger sizes
         * will be done as a series of accesses with smaller sizes.
         */
        unsigned max_access_size;
        /* If true, unaligned accesses are supported.  Otherwise all accesses
         * are converted to (possibly multiple) naturally aligned accesses.
         */
        bool unaligned;
    } impl;
};

其中的read和Write函數(shù)分別表示該MMIO的讀寫回調(diào);endianness表示字節(jié)的大小端模式。

以write回調(diào)函數(shù)為例,

    /* Write to the memory region. @addr is relative to @mr; @size is
     * in bytes. */
    void (*write)(void *opaque,
                  hwaddr addr,
                  uint64_t data,
                  unsigned size);
static void edu_mmio_write(void *opaque, hwaddr addr, uint64_t val,
                unsigned size)

其原型中的opaque表示的是設(shè)備的對(duì)象;addr表示虛擬機(jī)讀的地址在該MMIO中的偏移地址;data(val)表示要寫入的值;size表示寫入值的大小,通常由單字節(jié)、雙字節(jié)、四字節(jié)以及八字節(jié)。

edu_mmio_write函數(shù)同樣在hw/misc/edu.c中,代碼如下:

static void edu_mmio_write(void *opaque, hwaddr addr, uint64_t val,
                unsigned size)
{
    EduState *edu = opaque;

    if (addr < 0x80 && size != 4) {
        return;
    }

    if (addr >= 0x80 && size != 4 && size != 8) {
        return;
    }

    switch (addr) {
    case 0x04:
        edu->addr4 = ~val;
        break;
    case 0x08:
        if (qatomic_read(&edu->status) & EDU_STATUS_COMPUTING) {
            break;
        }
        /* EDU_STATUS_COMPUTING cannot go 0->1 concurrently, because it is only
         * set in this function and it is under the iothread mutex.
         */
        qemu_mutex_lock(&edu->thr_mutex);
        edu->fact = val;
        qatomic_or(&edu->status, EDU_STATUS_COMPUTING);
        qemu_cond_signal(&edu->thr_cond);
        qemu_mutex_unlock(&edu->thr_mutex);
        break;
    case 0x20:
        if (val & EDU_STATUS_IRQFACT) {
            qatomic_or(&edu->status, EDU_STATUS_IRQFACT);
            /* Order check of the COMPUTING flag after setting IRQFACT.  */
            smp_mb__after_rmw();
        } else {
            qatomic_and(&edu->status, ~EDU_STATUS_IRQFACT);
        }
        break;
    case 0x60:
        edu_raise_irq(edu, val);
        break;
    case 0x64:
        edu_lower_irq(edu, val);
        break;
    case 0x80:
        dma_rw(edu, true, &val, &edu->dma.src, false);
        break;
    case 0x88:
        dma_rw(edu, true, &val, &edu->dma.dst, false);
        break;
    case 0x90:
        dma_rw(edu, true, &val, &edu->dma.cnt, false);
        break;
    case 0x98:
        if (!(val & EDU_DMA_RUN)) {
            break;
        }
        dma_rw(edu, true, &val, &edu->dma.cmd, true);
        break;
    }
}

edu_mmio_write函數(shù)展示了一個(gè)虛擬機(jī)在寫設(shè)備MMIO地址時(shí)QEMU中設(shè)備模擬的典型行為。

(1)首先,需要檢查讀寫地址以及大小是否在范圍之內(nèi)。代碼片段如下:

    if (addr < 0x80 && size != 4) {
        return;
    }

    if (addr >= 0x80 && size != 4 && size != 8) {
        return;
    }

(2)然后,根據(jù)具體的地址來(lái)進(jìn)行適當(dāng)?shù)男袨椤?/p>

這些行為可以是簡(jiǎn)單地設(shè)置一個(gè)值,如這里的寫0x04地址,代碼片段如下:

    case 0x04:
        edu->addr4 = ~val;
        break;

也可以是將中斷設(shè)置為高電平(寫0x60地址)或者設(shè)置為低電平(寫0x64地址),代碼片段如下:

    case 0x60:
        edu_raise_irq(edu, val);
        break;
    case 0x64:
        edu_lower_irq(edu, val);
        break;

還可以是通過(guò)dma讀寫設(shè)備虛擬機(jī)的物理地址(寫0x80地址),代碼片段如下:

    case 0x80:
        dma_rw(edu, true, &val, &edu->dma.src, false);
        break;

對(duì)于read回調(diào)函數(shù),也是類似的機(jī)制。這里僅給出edu_mmio_read函數(shù)源碼,在hw/misc/edu.c中,代碼如下:

static uint64_t edu_mmio_read(void *opaque, hwaddr addr, unsigned size)
{
    EduState *edu = opaque;
    uint64_t val = ~0ULL;

    if (addr < 0x80 && size != 4) {
        return val;
    }

    if (addr >= 0x80 && size != 4 && size != 8) {
        return val;
    }

    switch (addr) {
    case 0x00:
        val = 0x010000edu;
        break;
    case 0x04:
        val = edu->addr4;
        break;
    case 0x08:
        qemu_mutex_lock(&edu->thr_mutex);
        val = edu->fact;
        qemu_mutex_unlock(&edu->thr_mutex);
        break;
    case 0x20:
        val = qatomic_read(&edu->status);
        break;
    case 0x24:
        val = edu->irq_status;
        break;
    case 0x80:
        dma_rw(edu, false, &val, &edu->dma.src, false);
        break;
    case 0x88:
        dma_rw(edu, false, &val, &edu->dma.dst, false);
        break;
    case 0x90:
        dma_rw(edu, false, &val, &edu->dma.cnt, false);
        break;
    case 0x98:
        dma_rw(edu, false, &val, &edu->dma.cmd, false);
        break;
    }

    return val;
}

欲知后事如何,且看下回分解。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-813522.html

到了這里,關(guān)于QEMU源碼全解析 —— PCI設(shè)備模擬(7)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • qemu源碼解析一

    qemu源碼解析一

    QEMU是一個(gè)開(kāi)源的虛擬化軟件,它能夠模擬各種硬件設(shè)備,支持多種虛擬化技術(shù),如TCG、Xen、KVM等 TCG 是 QEMU 中的一個(gè)組件,它可以將高級(jí)語(yǔ)言編寫的代碼(例如 C 代碼)轉(zhuǎn)換為可在虛擬機(jī)中執(zhí)行的低級(jí)代碼(例如 x86 機(jī)器指令)。TCG 生成的代碼通常比直接使用 CPU 指令更簡(jiǎn)單

    2024年04月12日
    瀏覽(14)
  • QEMU源碼全解析 —— virtio(20)

    QEMU源碼全解析 —— virtio(20)

    接前一篇文章: 上回書重點(diǎn)解析了virtio_pci_modern_probe函數(shù)。再來(lái)回顧一下其中相關(guān)的數(shù)據(jù)結(jié)構(gòu): struct virtio_pci_device struct virtio_pci_device的定義在Linux內(nèi)核源碼/drivers/virtio/virtio_pci_common.h中,如下: virtio_pci_modern_probe執(zhí)行完成后,相關(guān)數(shù)據(jù)結(jié)構(gòu)如下圖所示: 回到virtio_pci_probe函數(shù)

    2024年02月21日
    瀏覽(13)
  • QEMU源碼全解析38 —— Machine(8)

    QEMU源碼全解析38 —— Machine(8)

    接前一篇文章:QEMU源碼全解析37 —— Machine(7) 本文內(nèi)容參考: 《趣談Linux操作系統(tǒng)》 —— 劉超,極客時(shí)間 《QEMU/KVM》源碼解析與應(yīng)用 —— 李強(qiáng),機(jī)械工業(yè)出版社 特此致謝! 上一回經(jīng)過(guò)了重重周折,終于找到了MACHINE的定義所在: 本回就詳細(xì)解析一下這段代碼。別看代碼

    2024年02月12日
    瀏覽(9)
  • QEMU源碼全解析16 —— QOM介紹(5)

    接前一篇文章:QEMU源碼全解析15 —— QOM介紹(4) 本文內(nèi)容參考: 《趣談Linux操作系統(tǒng)》 —— 劉超,極客時(shí)間 《QEMU/KVM》源碼解析與應(yīng)用 —— 李強(qiáng),機(jī)械工業(yè)出版社 特此致謝! 上一回講完了QOM第一部分 —— 類型的注冊(cè)。本回開(kāi)始講解第二部分 —— 類型的初始化。 2. 類

    2024年02月15日
    瀏覽(12)
  • QEMU源碼全解析23 —— QOM介紹(12)

    接前一篇文章:QEMU源碼全解析22 —— QOM介紹(11) 本文內(nèi)容參考: 《趣談Linux操作系統(tǒng)》 —— 劉超,極客時(shí)間 《QEMU/KVM》源碼解析與應(yīng)用 —— 李強(qiáng),機(jī)械工業(yè)出版社 特此致謝! 上一回分析了QEMU對(duì)象的構(gòu)造和初始化的函數(shù)調(diào)用流程,本回結(jié)合實(shí)例對(duì)此流程進(jìn)行深入介紹和

    2024年02月14日
    瀏覽(13)
  • qemu-kvm IO優(yōu)化

    主要是磁盤方面的IO資源優(yōu)化 ?四個(gè)方面去著手優(yōu)化: 1. 磁盤的類型有IDE 、SATA 以及virtio 三種 ? 建議使用 virtio 2.?磁盤緩存模式 ? 目前KVM這塊支持5種磁盤緩存模式,writethrough、writeback、none、directsync或者unsafe。一般用到的就是前面3種,后面兩種幾乎不會(huì)使用。 ? writethrou

    2023年04月08日
    瀏覽(24)
  • kvm qemu虛擬機(jī)的創(chuàng)建和啟動(dòng)

    kvm qemu虛擬機(jī)的創(chuàng)建和啟動(dòng)

    qemu-img create -f qcow2 win1021H1.qcow2 10G sudo qemu-system-x86_64 -enable-kvm -m 8G -smp 4 -boot once=d -cdrom ./iso/cn_windows_7_enterprise_with_sp1_x64_dvd_u_677685.iso -hda ./win7_x64.qcow2 -vnc :1 -usb -usbdevice tablet 如果沒(méi)有指定-hda ./win7.qcow2,則在安裝系統(tǒng)的時(shí)候沒(méi)有磁盤,如下圖片是增加了之后才有的磁盤 默認(rèn)不

    2024年02月12日
    瀏覽(25)
  • 巨頁(yè)內(nèi)存與Qemu/KVM虛擬化內(nèi)存優(yōu)化

    巨頁(yè)內(nèi)存與Qemu/KVM虛擬化內(nèi)存優(yōu)化

    在虛擬化環(huán)境中,需要對(duì)虛擬機(jī)的優(yōu)化,其中包括在某些情況下利用巨頁(yè)內(nèi)存進(jìn)行內(nèi)存的優(yōu)化以提高虛擬機(jī)性能。那么什么是巨頁(yè)內(nèi)存?巨頁(yè)內(nèi)存有什么好處?Qemu/KVM虛擬化環(huán)境下如何使用巨頁(yè)內(nèi)存?本文將對(duì)這幾個(gè)問(wèn)題進(jìn)行闡述。 對(duì)于內(nèi)存管理,大多數(shù)現(xiàn)代操作系統(tǒng)都采用

    2024年02月07日
    瀏覽(26)
  • QEMU-KVM網(wǎng)絡(luò)特性協(xié)商與虛擬機(jī)通信

    深入了解QEMU-KVM在啟動(dòng)虛擬機(jī)時(shí)如何通過(guò)代理進(jìn)行網(wǎng)絡(luò)前后端特性協(xié)商,包括與DPDK vhost-user和guest virtio-net驅(qū)動(dòng)的交互。

    2024年02月01日
    瀏覽(22)
  • python可視化管理kvm虛擬機(jī)(使用libvirt、qemu連接虛擬機(jī))

    對(duì)于云計(jì)算的實(shí)踐,在虛擬機(jī)上面布置kvm虛擬機(jī)后使用python調(diào)用libvirt庫(kù)進(jìn)行遠(yuǎn)程可視化管理,實(shí)現(xiàn)輸出虛擬機(jī)信息、新建虛擬機(jī)、刪除虛擬機(jī)等功能,并在虛擬機(jī)集群上面運(yùn)行mpi代碼。 用pycharm專業(yè)版連接kvm的步驟見(jiàn)本文章。 mpi代碼見(jiàn)本文章。

    2024年02月16日
    瀏覽(14)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包