qemu虚拟化-设备模拟框架源码解析(sysbus模拟)

老规矩先看一下操作函数的注册过程

1.ops注册

ops的注册主要在memory_region_init_io函数:
memory.c

->memory_region_init_io
	->memory_region_init
	->mr->ops = ops ? ops : &unassigned_mem_ops;

qemu对IO地址空间和内存地址空间分别进行模拟,数据都保存在内存块(MemoryRegion)中。可以说qemu的设备模拟都是以内存快为基础的,内存块中保存了很多内存的描述信息,其中就包括了很重要的内存模拟相关的函数族ops。所以在讲解设备模拟之前有必要先说一下这个结构体。

2.MemoryRegion
struct MemoryRegion {
    Object parent_obj;

    /* All fields are private - violators will be prosecuted */

    /* The following fields should fit in a cache line */
    bool romd_mode;
    bool ram;
    bool subpage;
    bool readonly; /* For RAM regions */
    bool nonvolatile;
    bool rom_device;
    bool flush_coalesced_mmio;
    bool global_locking;
    uint8_t dirty_log_mask;
    bool is_iommu;
    RAMBlock *ram_block;
    Object *owner;

    const MemoryRegionOps *ops;
    void *opaque;
    MemoryRegion *container;
    Int128 size;
    hwaddr addr;
    void (*destructor)(MemoryRegion *mr);
    uint64_t align;
    bool terminates;
    bool ram_device;
    bool enabled;
    bool warning_printed; /* For reservations */
    uint8_t vga_logging_count;
    MemoryRegion *alias;
    hwaddr alias_offset;
    int32_t priority;
    QTAILQ_HEAD(subregions, MemoryRegion) subregions;
    QTAILQ_ENTRY(MemoryRegion) subregions_link;
    QTAILQ_HEAD(coalesced_ranges, CoalescedMemoryRange) coalesced;
    const char *name;
    unsigned ioeventfd_nb;
    MemoryRegionIoeventfd *ioeventfds;
};

内存块中暂时主要要关注is_iommu,ops这两个成员,这是设备模拟中很重要的两个成员。
之前已经讲过设备模拟的本质,设备模拟的框架无非是匹配上设备地址,然后调用设备的读写函数,理清四个流程就能弄清楚qemu设备模拟框架:io_readio_writemmio_readmmio_write

3.io_read

io_read从KVM_RUN系统调用过后开始分析:
kvm-all.c

->kvm_cpu_exec
	->kvm_handle_io
		->address_space_rw

exec.c

->address_space_rw
	->address_space_read_full
		->flatview_read
			->flatview_translate
			->flatview_read_continue
				->memory_region_dispatch_read

io地址对应到设备的逻辑就在flatview_translate,这个函数会根据地址找到设备对应的内存块,详细逻辑后面分析。

memory.c

->memory_region_dispatch_read
	->memory_region_dispatch_read1
		->memory_region_read_accessor
			->tmp = mr->ops->read(mr->opaque, addr, size);

内存块有了就可以用内存块中注册好的ops对内存数据进行模拟了。下面来看一下flatview_translate中的细节:
exec.c

->flatview_translate
	->flatview_do_translate
		->address_space_translate_internal
			->address_space_lookup_region
				->atomic_read(&d->mru_section);
				->phys_page_find(d, addr);
					->return &sections[lp.ptr];
				->atomic_set(&d->mru_section, section);
				->subpage = container_of(section->mr, subpage_t, iomem);
				->&d->map.sections[subpage->sub_section[SUBPAGE_IDX(addr)]];

atomic操作主要是做一个缓存加速,phys_page_find遍历地址空间寻找内存页,找到过后返回内存页对应的内存段。找到了内存段就等于找到了设备,可以使用设备的ops函数簇模拟了。这里除了使用phys_page_find查找内存还会查找subpage,一旦发现有subpage匹配会覆盖phys_page_find的结果,所以subpage的优先级会更高,这个会用在后面的地址空间扩展,比如pic模拟中对内存的管理。

4.io_write

相同部分省略
exec.c

->address_space_rw
	->address_space_write
		->flatview_write
			->flatview_translate
			->flatview_write_continue
				->memory_region_dispatch_write

后面的跟读的都是一样的,省略了

5.mmio_read/mmio_write

kvm-all.c

->kvm_cpu_exec
	->address_space_rw

mmio后面跟普通IO逻辑完全一样,调用的模拟函数也是一模一样。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值