qemu源码解析【03】qom实例

目录

  • qemu源码解析【03】qom实例
    • arm_sbcon_i2c实例

qemu源码解析【03】qom实例

arm_sbcon_i2c实例

  • 以hw/i2c/arm_sbcon_i2c.c代码为例,这个实例很简单,只用100行左右的代码,调用qemu系统接口实现了一个i2c硬件模拟
  • 先看include/hw/i2c/arm_sbcon_i2c.h头文件定义
#ifndef HW_I2C_ARM_SBCON_I2C_H
#define HW_I2C_ARM_SBCON_I2C_H#include "hw/sysbus.h"
#include "hw/i2c/bitbang_i2c.h"
#include "qom/object.h"// 定义类型名称,该名称会用type_register_static
// 注册到TypeInfo.name中
#define TYPE_ARM_SBCON_I2C "versatile_i2c"typedef struct ArmSbconI2CState ArmSbconI2CState;
DECLARE_INSTANCE_CHECKER(ArmSbconI2CState, ARM_SBCON_I2C, TYPE_ARM_SBCON_I2C)// 类型的私有数据结构
// 该数据结构的size会注册到TypeInfo.instance_size中
// 系统会根据这个size为我们分配内存
struct ArmSbconI2CState {/*< private >*/SysBusDevice parent_obj;/*< public >*/MemoryRegion iomem;bitbang_i2c_interface bitbang;int out;int in;
};#endif /* HW_I2C_ARM_SBCON_I2C_H */
  • 分析一下上面的:DECLARE_INSTANCE_CHECKER(ArmSbconI2CState, ARM_SBCON_I2C, TYPE_ARM_SBCON_I2C)
    初步展开这个宏会变成:
static inline G_GNUC_UNUSED ArmSbconI2CState * \
ARM_SBCON_I2C(const void *obj) \
{ return OBJECT_CHECK(ArmSbconI2CState, obj, TYPE_ARM_SBCON_I2C); }
  • 再接着展开会变成:
static inline G_GNUC_UNUSED ArmSbconI2CState *ARM_SBCON_I2C(const void *obj) \
{return ((ArmSbconI2CState *)object_dynamic_cast_assert(OBJECT(obj), (TYPE_ARM_SBCON_I2C), \__FILE__, __LINE__, __func__));
}
  • object_dynamic_cast_assert()函数就不继续展开了,这个函数注释里面这样写道:perform type safe dynamic_casts to this object type,看起来就是一个指针类型的动态转换。所以这里定义了一个函数ARM_SBCON_I2C(),将给定的(void *)obj内存动态转换成(ArmSbconI2CState *)类型
  • 后面在arm_sbcon_i2c_init()函数中我们也可以看到,ArmSbconI2CState *s = ARM_SBCON_I2C(obj)这条语句正是使用了这个数据类型转换的功能
  • 再看hw/i2c/arm_sbcon_i2c.c具体实现,具体解析都写在注释中了
#include "qemu/osdep.h"
#include "hw/i2c/arm_sbcon_i2c.h"
#include "hw/registerfields.h"
#include "qemu/log.h"
#include "qemu/module.h"
#include "qom/object.h"// 声明该i2c硬件的寄存器
REG32(CONTROL_GET, 0)
REG32(CONTROL_SET, 0)
REG32(CONTROL_CLR, 4)#define SCL BIT(0)
#define SDA BIT(1)// 声明i2c read函数,注册到后面的arm_sbcon_i2c_ops结构体中
static uint64_t arm_sbcon_i2c_read(void *opaque, hwaddr offset,unsigned size)
{ArmSbconI2CState *s = opaque;// 解析寄存器参数switch (offset) {case A_CONTROL_SET:return (s->out & 1) | (s->in << 1);default:qemu_log_mask(LOG_GUEST_ERROR,"%s: Bad offset 0x%x\n", __func__, (int)offset);return -1;}
}// 声明i2c write函数,注册到后面的arm_sbcon_i2c_ops结构体中
static void arm_sbcon_i2c_write(void *opaque, hwaddr offset,uint64_t value, unsigned size)
{ArmSbconI2CState *s = opaque;// 解析寄存器参数switch (offset) {case A_CONTROL_SET:s->out |= value & 3;break;case A_CONTROL_CLR:s->out &= ~value;break;default:qemu_log_mask(LOG_GUEST_ERROR,"%s: Bad offset 0x%x\n", __func__, (int)offset);}// 调用bitbang模拟I2C时序bitbang_i2c_set(&s->bitbang, BITBANG_I2C_SCL, (s->out & SCL) != 0);s->in = bitbang_i2c_set(&s->bitbang, BITBANG_I2C_SDA, (s->out & SDA) != 0);
}// 定义了memory region上面绑定的操作函数,后面使用memory_region_init_io,在声明memory region的时候进行注册
static const MemoryRegionOps arm_sbcon_i2c_ops = {.read = arm_sbcon_i2c_read,.write = arm_sbcon_i2c_write,.endianness = DEVICE_NATIVE_ENDIAN,
};static void arm_sbcon_i2c_init(Object *obj)
{DeviceState *dev = DEVICE(obj);// 在头文件中用DECLARE_INSTANCE_CHECKER(ArmSbconI2CState, ARM_SBCON_I2C, TYPE_ARM_SBCON_I2C)// 已经声明了ARM_SBCON_I2C()函数ArmSbconI2CState *s = ARM_SBCON_I2C(obj);SysBusDevice *sbd = SYS_BUS_DEVICE(obj);I2CBus *bus;// qemu系统的i2c函数,创建一个i2c总线bus = i2c_init_bus(dev, "i2c");// i2c bitbang,软件层通过IO脚去模拟I2C的时序,从而实现I2C协议bitbang_i2c_init(&s->bitbang, bus);// 分配一块memory空间,用来做io操作// 其实就是模拟硬件的寄存器地址空间// 注意这里将ArmSbconI2CState *s指针作为参数传进去// 后面每次调用io操作的时候,都会作为void *opaque参数memory_region_init_io(&s->iomem, obj, &arm_sbcon_i2c_ops, s,"arm_sbcon_i2c", 0x1000);sysbus_init_mmio(sbd, &s->iomem);
}static const TypeInfo arm_sbcon_i2c_info = {// 类型名称.name          = TYPE_ARM_SBCON_I2C,// 类型的父类型.parent        = TYPE_SYS_BUS_DEVICE,// 类型的数据size.instance_size = sizeof(ArmSbconI2CState),// 注册类型的初始化函数.instance_init = arm_sbcon_i2c_init,
};static void arm_sbcon_i2c_register_types(void)
{// 调用系统接口注册类型type_register_static(&arm_sbcon_i2c_info);
}type_init(arm_sbcon_i2c_register_types)

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

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

相关文章

小程序自定义tab-bar,踩坑记录

从官方下载代码 https://developers.weixin.qq.com/miniprogram/dev/framework/ability/custom-tabbar.html 1、把custom-tab-bar 文件放置 pages同级 修改下 custom-tab-bar 下的 JS文件 Component({data: {selected: 0,color: "#7A7E83",selectedColor: "#3…

操作系统(14)请求分页

前言 操作系统中的请求分页&#xff0c;也称为页式虚拟存储管理&#xff0c;是建立在基本分页基础上&#xff0c;为了支持虚拟存储器功能而增加了请求调页功能和页面置换功能的一种内存管理技术。 一、基本概念 分页&#xff1a;将进程的逻辑地址空间分成若干个大小相等的页&am…

git企业开发的相关理论(一)

目录 一.初识git 二.git的安装 三.初始化/创建本地仓库 四.配置用户设置/配置本地仓库 五.认识工作区、暂存区、版本库 六.添加文件__场景一 七.查看 .git 文件/添加到本地仓库后.git中发生的变化 1.执行git add后的变化 index文件&#xff08;暂存区&#xff09; log…

wxpython图形用户界面编程

wxpython图形用户界面编程 一、wxpython的基础 1.1 wxpython的基础 作为图形用户界面开发工具包 wxPython&#xff0c;主要提供了如下 GUI 内容&#xff1a; 窗口。控件。事件处理。布局管理。 1.2 wxpython的类层次机构 1.3 wxpython的安装 Windows 和 macOS 平台安装&a…

水仙花数(流程图,NS流程图)

题目&#xff1a;打印出所有的100-999之间的"水仙花数"&#xff0c;并画出流程图和NS流程图。所谓"水仙花数"是指一个三位数&#xff0c;其各位数字立方和等于该数本身。例如&#xff1a;153是一个"水仙花数"&#xff0c;因为1531的三次方&#…

不配置python环境,直接用PyCharm就可以?

有的伙伴可能遇到不安装python环境只安装pycharm也可以进行运行代码。 所以自认为是不需要解释器就可以运行&#xff1f; 这个是不现实的&#xff0c;有很多伙伴可能是安装了Pycharm&#xff0c;但Pycharm看你电脑上没有解释器&#xff0c;所以在安装的时候给你默认安装在C盘…

网络安全渗透测试概论

渗透测试&#xff0c;也称为渗透攻击测试是一种通过模拟恶意攻击者的手段来评估计算机系统、网络或应用程序安全性的方法。 目的 旨在主动发现系统中可能存在的安全漏洞、脆弱点以及潜在风险&#xff0c;以便在被真正的恶意攻击者利用之前&#xff0c;及时进行修复和加固&…

爬虫数据能用于商业吗?

在当今数字化时代&#xff0c;数据已成为企业获取竞争优势的关键资源。网络爬虫作为一种数据收集工具&#xff0c;能够从互联网上抓取大量数据&#xff0c;这些数据在商业分析中扮演着重要角色。然而&#xff0c;使用爬虫技术获取的数据是否合法、能否用于商业分析&#xff0c;…

前端面试汇总(不定时更新)

目录 HTML & CSS1. XML、HTML、XHTML 有什么区别&#xff1f;⭐2. XML和JSON的区别&#xff1f;3. 是否了解W3C的规范&#xff1f;⭐4. 什么是语义化标签&#xff1f;⭐⭐5. 行内元素和块级元素的区别&#xff1f;⭐6. 行内元素和块级元素的转换&#xff1f;⭐7. 常用的块级…

SpringCloud微服务实战系列:03spring-cloud-gateway业务网关灰度发布

目录 spring-cloud-gateway 和zuul spring webflux 和 spring mvc spring-cloud-gateway 的两种模式 spring-cloud-gateway server 模式下配置说明 grayLb://system-server 灰度发布代码实现 spring-cloud-gateway 和zuul zuul 是spring全家桶的第一代网关组件&#x…

QT3学习之进阶理解信号和槽:如何自定义一个类信号,供其它类调用槽函数

下面是QWidget源码&#xff0c;定义了两个事件 /*!This event handler can be reimplemented in a subclass to receivewidget enter events.An event is sent to the widget when the mouse cursor enters thewidget.\sa leaveEvent(), mouseMoveEvent(), event() */void QWi…

GaLore和Q-GaLore:一种记忆高效的预训练和微调策略,用于大型语言模型(LLMs)

GaLore和Q-GaLore&#xff1a;一种记忆高效的预训练和微调策略&#xff0c;用于大型语言模型&#xff08;LLMs&#xff09; GaLore和Q-GaLore的设计背景、工作原理及其优势 设计背景 随着大型语言模型&#xff08;LLMs&#xff09;的发展&#xff0c;模型的规模和复杂性不断…

【网络云计算】2024第51周-每日【2024/12/17】小测-理论-解析

文章目录 1. 计算机网络有哪些分类2. 计算机网络中协议与标准的区别3. 计算机网络拓扑有哪些结构4. 常用的网络设备有哪些&#xff0c;分属于OSI的哪一层5. IEEE802局域网标准有哪些 【网络云计算】2024第51周-每日【2024/12/17】小测-理论-解析 1. 计算机网络有哪些分类 计算…

ActiveMQ 反序列化漏洞CVE-2015-5254复现

文章目录 一、产生原因二、利用条件三、利用过程四、PoC&#xff08;概念验证&#xff09;五、poc环境验证使用find搜索vulhub已安装目录打开activeMQ组件查看配置文件端口启动镜像-文件配置好后对于Docker 镜像下载问题及解决办法设置好镜像源地址&#xff0c;进行重启docker查…

shardingsphere分库分表跨库访问 添加分片规则

shardingsphere分库分表跨库访问 添加分片规则 建立 JDBC 环境 创建表 t_order&#xff1a; CREATE TABLE t_order (tid bigint(20) NOT NULL,tname varchar(255) DEFAULT NULL,goods_id bigint(20) DEFAULT NULL,tstatus varchar(255) DEFAULT NULL,PRIMARY KEY (tid) ) E…

C++ 中,构造函数、拷贝构造函数和移动构造函数区别

在 C 中&#xff0c;构造函数、拷贝构造函数和移动构造函数是类中用于对象初始化的三种不同类型的构造函数。它们的功能和使用场景有所不同&#xff0c;下面详细解释它们之间的区别。 1. 构造函数 (Constructor) 定义&#xff1a; 构造函数是一个特殊的成员函数&#xff0c;用…

MYSQL执行一条update语句,期间发生了什么

客户端先通过连接器建立连接&#xff0c;连接器自会判断用户身份&#xff1b; 因为这是一条 update 语句&#xff0c;所以不需要经过查询缓存&#xff0c;但是表上有更新语句&#xff0c;是会把整个表的查询缓存清空的&#xff0c;所以说查询缓存很鸡肋&#xff0c;在 MySQL 8…

vue3监听横向滚动条的位置;鼠标滚轮滑动控制滚动条滚动;监听滚动条到顶端

1.横向取值scrollLeft 竖向取值scrollTop 2.可以监听到最左最右侧 3.鼠标滚轮滑动控制滚动条滚动 效果 <template><div><div class"scrollable" ref"scrollableRef"><!-- 内容 --><div style"width: 2000px; height: 100…

深入理解MyBatis的Mapper层:让数据访问更高效

目录 1. 什么是MyBatis的Mapper层&#xff1f; 1.1 典型的Mapper层结构 1.2 示例&#xff1a;一个简单的用户管理系统 2. 创建Mapper层 2.1 创建实体类 2.2 创建Mapper接口 2.3 创建Mapper XML文件&#xff08;可选&#xff09; 2.4 配置MyBatis的SQL映射 3. 使用Mapp…

WPF xaml 文件详解

<div id"content_views" class"htmledit_views"><h2><a name"t0"></a>1.总述</h2> 创建好了WPF项目后&#xff0c;最重要的是对 App和MainWindow的理解&#xff0c;在一开始的时候&#xff0c;极容易就直接在Main…