QEMU源码全解析23 —— QOM介绍(12)

接前一篇文章:QEMU源码全解析22 —— QOM介绍(11)

本文内容参考:

《趣谈Linux操作系统》 —— 刘超,极客时间

《QEMU/KVM》源码解析与应用 —— 李强,机械工业出版社

特此致谢!

上一回分析了QEMU对象的构造和初始化的函数调用流程,本回结合实例对此流程进行深入介绍和解析。

仍以前文的edu的TypeInfo为例。再次贴出edu相关代码如下(hw/misc/edu.c中):

static void pci_edu_register_types(void)
{static InterfaceInfo interfaces[] = {{ INTERFACE_CONVENTIONAL_PCI_DEVICE },{ },};static const TypeInfo edu_info = {.name          = TYPE_PCI_EDU_DEVICE,.parent        = TYPE_PCI_DEVICE,.instance_size = sizeof(EduState),.instance_init = edu_instance_init,.class_init    = edu_class_init,.interfaces = interfaces,};type_register_static(&edu_info);
}
type_init(pci_edu_register_types)

edu的对象大小为sizeof(EduState),因此实际上一个edu类型的对象是EduState结构体,每一个对象都会有一个XXXState与之对应,记录了该对象的相关信息。若edu是一个PCI设备,则EduState中就会有这个设备的一些信息,如:中断信息、设备状态、使用的MMIO和PIO对应的内存区域等。

在object_init_with_type函数中可以看到,调用的参数都是一个Object,却能够一直调用父类型的初始化函数,不出意外这里也会有一个层次关系。为了便于理解,再次贴出相关代码:

static void object_init_with_type(Object *obj, TypeImpl *ti)
{if (type_has_parent(ti)) {object_init_with_type(obj, type_get_parent(ti));}if (ti->instance_init) {ti->instance_init(obj);}
}

具体来看一下EduState结构,其定义在hw/misc/edu.c中,如下所示:

struct EduState {PCIDevice pdev;MemoryRegion mmio;QemuThread thread;QemuMutex thr_mutex;QemuCond thr_cond;bool stopping;uint32_t addr4;uint32_t fact;
#define EDU_STATUS_COMPUTING    0x01
#define EDU_STATUS_IRQFACT      0x80uint32_t status;uint32_t irq_status;#define EDU_DMA_RUN             0x1
#define EDU_DMA_DIR(cmd)        (((cmd) & 0x2) >> 1)
# define EDU_DMA_FROM_PCI       0
# define EDU_DMA_TO_PCI         1
#define EDU_DMA_IRQ             0x4struct dma_state {dma_addr_t src;dma_addr_t dst;dma_addr_t cnt;dma_addr_t cmd;} dma;QEMUTimer dma_timer;char dma_buf[DMA_SIZE];uint64_t dma_mask;
};

关注其中第一个成员的类型:PCIDevice结构。其与pci_device_type_info对应,代码如下(hw/pci/pci.c中):

static const TypeInfo pci_device_type_info = {.name = TYPE_PCI_DEVICE,.parent = TYPE_DEVICE,.instance_size = sizeof(PCIDevice),.abstract = true,.class_size = sizeof(PCIDeviceClass),.class_init = pci_device_class_init,.class_base_init = pci_device_class_base_init,
};

struct PCIDevice在include/hw/pci/pci.h中定义,代码如下:

struct PCIDevice {DeviceState qdev;bool partially_hotplugged;bool has_power;/* PCI config space */uint8_t *config;/* Used to enable config checks on load. Note that writable bits are* never checked even if set in cmask. */uint8_t *cmask;/* Used to implement R/W bytes */uint8_t *wmask;/* Used to implement RW1C(Write 1 to Clear) bytes */uint8_t *w1cmask;/* Used to allocate config space for capabilities. */uint8_t *used;/* the following fields are read only */int32_t devfn;/* Cached device to fetch requester ID from, to avoid the PCI* tree walking every time we invoke PCI request (e.g.,* MSI). For conventional PCI root complex, this field is* meaningless. */PCIReqIDCache requester_id_cache;char name[64];PCIIORegion io_regions[PCI_NUM_REGIONS];AddressSpace bus_master_as;MemoryRegion bus_master_container_region;MemoryRegion bus_master_enable_region;/* do not access the following fields */PCIConfigReadFunc *config_read;PCIConfigWriteFunc *config_write;/* Legacy PCI VGA regions */MemoryRegion *vga_regions[QEMU_PCI_VGA_NUM_REGIONS];bool has_vga;/* Current IRQ levels.  Used internally by the generic PCI code.  */uint8_t irq_state;/* Capability bits */uint32_t cap_present;/* Offset of MSI-X capability in config space */uint8_t msix_cap;/* MSI-X entries */int msix_entries_nr;/* Space to store MSIX table & pending bit array */uint8_t *msix_table;uint8_t *msix_pba;/* May be used by INTx or MSI during interrupt notification */void *irq_opaque;MSITriggerFunc *msi_trigger;MSIPrepareMessageFunc *msi_prepare_message;MSIxPrepareMessageFunc *msix_prepare_message;/* MemoryRegion container for msix exclusive BAR setup */MemoryRegion msix_exclusive_bar;/* Memory Regions for MSIX table and pending bit entries. */MemoryRegion msix_table_mmio;MemoryRegion msix_pba_mmio;/* Reference-count for entries actually in use by driver. */unsigned *msix_entry_used;/* MSIX function mask set or MSIX disabled */bool msix_function_masked;/* Version id needed for VMState */int32_t version_id;/* Offset of MSI capability in config space */uint8_t msi_cap;/* PCI Express */PCIExpressDevice exp;/* SHPC */SHPCDevice *shpc;/* Location of option rom */char *romfile;uint32_t romsize;bool has_rom;MemoryRegion rom;uint32_t rom_bar;/* INTx routing notifier */PCIINTxRoutingNotifier intx_routing_notifier;/* MSI-X notifiers */MSIVectorUseNotifier msix_vector_use_notifier;MSIVectorReleaseNotifier msix_vector_release_notifier;MSIVectorPollNotifier msix_vector_poll_notifier;/* ID of standby device in net_failover pair */char *failover_pair_id;uint32_t acpi_index;
};

同样关注第一个成员的类型:DeviceState结构。其与device_type_info对应,代码如下(hw/core/qdev.c):

static const TypeInfo device_type_info = {.name = TYPE_DEVICE,.parent = TYPE_OBJECT,.instance_size = sizeof(DeviceState),.instance_init = device_initfn,.instance_post_init = device_post_init,.instance_finalize = device_finalize,.class_base_init = device_class_base_init,.class_init = device_class_init,.abstract = true,.class_size = sizeof(DeviceClass),.interfaces = (InterfaceInfo[]) {{ TYPE_VMSTATE_IF },{ TYPE_RESETTABLE_INTERFACE },{ }}
};

struct DeviceState在include/hw/qdev-core.h中定义,代码如下:

/*** DeviceState:* @realized: Indicates whether the device has been fully constructed.*            When accessed outside big qemu lock, must be accessed with*            qatomic_load_acquire()* @reset: ResettableState for the device; handled by Resettable interface.** This structure should not be accessed directly.  We declare it here* so that it can be embedded in individual device state structures.*/
struct DeviceState {/*< private >*/Object parent_obj;/*< public >*/char *id;char *canonical_path;bool realized;bool pending_deleted_event;int64_t pending_deleted_expires_ms;QDict *opts;int hotplugged;bool allow_unplug_during_migration;BusState *parent_bus;QLIST_HEAD(, NamedGPIOList) gpios;QLIST_HEAD(, NamedClockList) clocks;QLIST_HEAD(, BusState) child_bus;int num_child_bus;int instance_id_alias;int alias_required_for_version;ResettableState reset;GSList *unplug_blockers;
};

通过以上edu_info、pci_device_type_info、device_type_info和与之对应的EduState、PCIDevice、DeviceState的定义可以看出,对象之间其实也是有一种父对象与子对象的关系存在。与类型一样,QOM中的对象也可以使用宏,将一个指向Object对象的指针转换成一个指向子类对象的指针,转换过程与类型ObjectClass类似,在此不在赘述。

这里可以看出,不同于类型信息和类型,object是根据需要创建的,只有在命令行指定了设备或者是热插拔一个设备之后才会有object的创建。类型和对象之间是通过Object的Class域联系在一起的。这是在object_initialize_with_type函数中通过obj->class = type->class实现的。对应代码再次贴出(qom/object.c中):

static void object_initialize_with_type(Object *obj, size_t size, TypeImpl *type)
{type_initialize(type);g_assert(type->instance_size >= sizeof(Object));g_assert(type->abstract == false);g_assert(size >= type->instance_size);memset(obj, 0, type->instance_size);obj->class = type->class;object_ref(obj);object_class_property_init_all(obj);obj->properties = g_hash_table_new_full(g_str_hash, g_str_equal,NULL, object_property_free);object_init_with_type(obj, type);object_post_init_with_type(obj, type);
}

综合前文(从QEMU源码全解析 —— QOM介绍(1)开始),可以把QOM的对象构造成三部分:第一部分是类型的构造,通过TypeInfo构造一个TypeImpl的哈希表,这是在主函数main之前完成的;第二部分是类型的初始化,这两部分都是全局的,即只要编译进去的QOM对象都会被调用;第三部分是类对象的构造,这是构造具体的对象实例,只有在命令行指定了对应的设备时,才会创建对象。

类比C++、Java等高级语言中的反射机制:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/17066.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【计算机网络】网络层协议 -- IP协议

文章目录 1. 网络层做了什么事2. IP协议的简介3. IP协议格式4. 分片与组装5. 网段划分6. 特殊的IP地址7. IP地址的数量限制8. 私网IP地址和公网IP地址9. 路由 1. 网络层做了什么事 保证数据可靠地从一台主机到另一台主机 当双方在进行基于TCP的网络通信时&#xff0c;要保证将数…

解决uniapp的tabBar使用iconfont图标显示方块

今天要写个uniapp的移动端项目&#xff0c;底部tabBar需要添加图标&#xff0c;以往都是以图片的形式引入&#xff0c;但是考虑到不同甲方的主题色也不会相同&#xff0c;使用图片的话&#xff0c;后期变换主题色并不友好&#xff0c;所以和UI商量之后&#xff0c;决定使用icon…

HCIP OSPF链路状态类型总结

OSPF的LSA OSPF是典型的链路状态路由协议&#xff0c;使用LAS&#xff08;链路状态通告&#xff09;来承载链路状态信息。LSA是OSPF的一个核心内容&#xff0c;如果没有LSA&#xff0c;OSPF 是无法描述网络的拓扑结构及网段信息的&#xff0c;也无法传递路由信息&#xff0c;更…

hbuilderx主题色分享-github风格

效果 步骤 hbuilderx总共有三种主题&#xff0c;绿柔主题Default,酷黑主题Monokai,雅黑主题Atom One Dark,修改主题色是基于三种主题之一的&#xff0c;不能直接创建一个新主题&#xff0c;比如下方配置是基于Atom One Dark(对象名为[Atom One Dark])&#xff0c;则当前hbuild…

Stream API:Java 8 编程的秘密武器

Stream API 是 Java 8 中最重要的新特性之一&#xff0c;它是处理集合和数组的一种新方式。它提供了一种简单、灵活和可读的方式来处理集合和数组中的元素&#xff0c;从而使代码更加简洁、高效和易于维护。 1. 原理介绍 Stream API 的核心是 Stream 接口&#xff0c;它表示一…

union和union all

union 是一个计算机函数&#xff0c;用于合并两个或多个 SELECT 语句的结果集。 请注意&#xff0c;UNION 内部的 SELECT 语句必须拥有相同数量的列。列也必须拥有相似的数据类型。同时&#xff0c;每条 SELECT 语句中的列的顺序必须相同。 union 语法&#xff1a; select …

Profinet转EtherNet/IP网关连接AB PLC的应用案例

西门子S7-1500 PLC&#xff08;profinet&#xff09;与AB PLC以太网通讯&#xff08;EtherNet/IP&#xff09;。本文主要介绍捷米特JM-EIP-PN的Profinet转EtherNet/IP网关&#xff0c;连接西门子S7-1500 PLC与AB PLC 通讯的配置过程&#xff0c;供大家参考。 1, 新建工程&…

06-MySQL-基础篇-SQL之DCL语句

SQL之DCL语句 前言DCL 管理用户查询用户创建用户修改用户密码删除用户说明 权限控制常见权限描述查询权限授予权限撤销权限说明 前言 本篇来学习下SQL中的DCL语句 DCL DCL英文全称是Data Control Language(数据控制语言)&#xff0c;用来管理数据库用户、控制数据库的访问权…

有哪些类似bootstrap的纯css框架?

前言 下面是一些类似bootstrap的css框架&#xff0c;以及其开源的仓库和网址附上&#xff0c;整理不易&#xff0c;希望多多点一下赞同收藏喜欢哈~ 1、Tailwind Star&#xff1a;70.5k Tailwind CSS 是一个实用的工具集&#xff0c;用于快速构建现代化的自定义用户界面。它提…

7、单元测试--测试RestFul 接口

单元测试–测试RestFul 接口 – 测试用例类使用SpringBootTest(webEnvironment WebEnvironment.RANDOM_PORT)修饰。 – 测试用例类会接收容器依赖注入TestRestTemplate这个实例变量。 – 测试方法可通过TestRestTemplate来调用RESTful接口的方法。 测试用例应该定义在和被测…

vue2实现一个树型控件(支持展开树与checkbox勾选)

目录 vue2实现一个树型控件(支持展开树与checkbox勾选)TreeItem.vueTree.vue效果 vue2实现一个树型控件(支持展开树与checkbox勾选) TreeItem.vue <template><div class"tree-item"><span click"toggleExpanded" class"icon" v…

Sentinel Dashboard集成Nacos

1.前言 当项目上Sentinel Dashboard做流量监控的时候&#xff0c;我们可以通过Sentinel控制台修改限流配置&#xff0c;但当我们使用Nacos作为配置中心动态配置流控规则的时候&#xff0c;问题就来了。 首先我们要明白&#xff0c;Sentinel Dashboard的配置是从机器的内存中加…

TCP网络通信编程之网络上传文件

【图片】 【思路解析】 【客户端代码】 import java.io.*; import java.net.InetAddress; import java.net.Socket; import java.net.UnknownHostException;/*** ProjectName: Study* FileName: TCPFileUploadClient* author:HWJ* Data: 2023/7/29 18:44*/ public class TCPFil…

【SpringBoot笔记36】SpringBoot自定义WebSocketHandler集成WebSocket

这篇文章,主要介绍SpringBoot自定义WebSocketHandler集成WebSocket。 目录 一、SpringBoot集成WebSocket 1.1、添加WebSocket依赖 1.2、自定义WebSocketHandler 1.3、注册WebSocket服务端

NoSQL--------- Redis配置与优化

目录 一、关系型数据库与非关系型数据库 1.1关系型数据库 1.2非关系型数据库Nosql 1.3关系与非关系区别 1.4非关系产生的背景 1.5总结 二、Redis介绍 2.1Redis简介 2.3Redis优点 2.4 Redis为什么这么快&#xff1f; 三、Redis安装部署 3.1安装redis 3.2测试redis 3.3r…

【论文简述】DIP: Deep Inverse Patchmatch for High-Resolution Optical Flow(CVPR 2022)

一、论文简述 1. 第一作者&#xff1a;Rui Li 2. 发表年份&#xff1a;2023 3. 发表期刊&#xff1a;CVPR 4. 关键词&#xff1a;光流、深度学习、PatchMatch、局部搜索 5. 探索动机&#xff1a;对于深度学习来说&#xff0c;除了准确性之外&#xff0c;性能和内存也是一个…

基于深度学习的CCPD车牌检测系统(PyTorch+Pyside6+YOLOv5模型)

摘要&#xff1a;基于CCPD数据集的高精度车牌检测系统可用于日常生活中检测与定位车牌目标&#xff0c;利用深度学习算法可实现图片、视频、摄像头等方式的车牌目标检测识别&#xff0c;另外支持结果可视化与图片或视频检测结果的导出。本系统采用YOLOv5目标检测模型训练数据集…

回归预测 | MATLAB实现GRNN广义回归神经网络多输入单输出回归预测(多指标,多图)

回归预测 | MATLAB实现GRNN广义回归神经网络多输入单输出回归预测(多指标,多图) 目录 回归预测 | MATLAB实现GRNN广义回归神经网络多输入单输出回归预测(多指标,多图)效果一览基本介绍程序设计参考资料效果一览 基本介绍 MATLAB实现GRNN广义回归神经网络多输入单输出回归…

centos动态内网IP如何改静态

要将CentOS从动态内网IP改为静态IP&#xff0c;需要按照以下步骤进行操作&#xff1a; 打开终端并以root用户身份登录。 编辑网络配置文件。在终端中输入以下命令&#xff1a; vi /etc/sysconfig/network-scripts/ifcfg-eth0 这个命令将打开eth0配置文件。如果您的网络接口…

GitLab备份升级

数据备份(默认的备份目录在/var/opt/gitlab/backups/下&#xff0c;生成一个以时间节点命名的tar包。) gitlab-rake gitlab:backup:create新建repo源&#xff0c;升级新版本的gitlab vim /etc/yum.repos.d/gitlab-ce.repo [gitlab-ce] namegitlab-ce baseurlhttps://mirrors.…