(1) 添加xxx设备到QEMU
// 这是一个用于在QEMU虚拟机中添加设备的函数。
// 它接受一个指向SigiEVirt结构的指针和一个整数作为参数。
static void sigie_add_xxx(SigiEVirt *s, int id)
{
// 声明了两个MemoryRegion指针,一个用于表示设备的内存区域,另一个用于表示系统内存。
MemoryRegion *mr;
MemoryRegion *sysmem = get_system_memory();
// 获取指向虚拟机中GIC设备的指针。
DeviceState *gicdev = DEVICE(&s->apu.gic);
// 获取基地址,这是一个用于内存映射的地址。
hwaddr base = base_memmap[id].base;
// 创建一个包含一个中断的整数数组irqs。
int irqs[1] = {SIGI_xxx0_IRQ_0};
// 使用qdev_new函数创建一个名为"xxx"的设备,类型为HOBOT_xxx。
s->xxx = qdev_new(TYPE_HOBOT_xxx);
// 实例化并释放"xxx"设备,并处理可能出现的致命错误。
sysbus_realize_and_unref(SYS_BUS_DEVICE(s->xxx), &error_fatal);
// 获取"xxx"设备的内存映射IO区域,并将其赋值给mr。
mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(s->xxx[i]), 0);
// 将"xxx"设备的内存映射IO区域添加为系统内存区域的子区域。
memory_region_add_subregion(sysmem, base, mr);
// 连接"xxx"设备的第一个中断(IRQ 0)到GIC设备的输入GPIO中,
// 以便在中断触发时触发中断处理程序。
sysbus_connect_irq(SYS_BUS_DEVICE(s->xxx), 0, qdev_get_gpio_in(gicdev, irqs[i]));
}
// 这是一个用于虚拟机设备实例化的函数。
static void sigi_virt_realize(DeviceState *dev, Error **errp)
{
// 将传递给函数的设备状态指针强制转换为SigiEVirt结构的指针,方便后续操作。
SigiEVirt *s = SIGIE_VIRT(dev);
................
// 调用sigie_add_xxx函数,将一个名为"xxx"的设备添加到虚拟机中。
// VIRT_xxx是一个参数,用于标识要添加的设备的类型。
sigie_add_xxx(s, VIRT_xxx0);
................
}
(2) 定义地址空间中断等资源
static const MemMapEntry base_memmap[] = {
................
[VIRT_xxx] = { 0x37C80000, 0x00010000 },
................
}
//在虚拟soc的结构体中添加设备描述
DeviceState *xxx[1];
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; // 与设备关联的GPIO列表
QLIST_HEAD(, NamedClockList) clocks; // 与设备关联的时钟列表
QLIST_HEAD(, BusState) child_bus; // 与设备关联的子总线列表
int num_child_bus; // 子总线的数量
int instance_id_alias; // 实例ID的别名
int alias_required_for_version; // 版本所需的别名
ResettableState reset; // 设备的复位状态
GSList *unplug_blockers; // 阻止设备卸载的列表
};
(3)设备头文件描述
#include "qemu/fifo64.h" // 包含FIFO64相关的头文件
#include "SOC/utils/SOC_image_buf.h" // 包含SOC_image_buf相关的头文件
#define TYPE_SOC_xxx "SOC_xxx" // 定义了设备类型的名称
#define SOC_xxx_OBJECT(obj) OBJECT_CHECK(SOCxxxState, (obj), TYPE_SOC_xxx) // 检查对象是否是SOCxxxState类型
#define SOC_xxx_CLASS(klass) OBJECT_CLASS_CHECK(SOCxxxClass, (klass), TYPE_SOC_xxx) // 检查类是否是SOCxxxClass类型
#define SOC_xxx_GET_CLASS(obj) OBJECT_GET_CLASS(SOCxxxClass, (obj), TYPE_SOC_xxx) // 获取对象的类
#define SOC_xxx_ADDR_FIFO_SIZE (16) // 定义了地址FIFO的大小
/* xxx ddr start reg */
#define xxx_DDR_START (1 << 0) // 定义了xxx DDR启动标志位
/* xxx int status reg */
enum xxx_interrupt_map {
INTR_xxx_BUSY,
INTR_xxx_ERROR,
INTR_xxx_CONF_ERROR = 8,
INTR_xxx_USER_ABORT,
INTR_xxx_AXI_READER_ERROR,
INTR_xxx_AXI_WRITER_ERROR,
INTR_xxx_UNALIGNED_ACCESS,
INTR_xxx_INCOMPATIBLE_CONF,
};
// 定义了xxx设备的中断映射枚举,表示不同的中断类型
enum xxx_reg {
xxx_ID,
xxx_CONFIG_ADDR = 0x10 >> 2,
xxx_CONFIG_SIZE,
xxx_STATUS,
xxx_PROCESS_CONFIG,
xxx_AXI_SETTING_CONFIG_READER,
xxx_AXI_SETTING_TILE_READER,
xxx_AXI_SETTING_TILE_WRITER,
xxx_INT_STATUS = 0x200 >> 2,
xxx_INT_MASK = 0x204 >> 2,
NUM_OF_xxx_REG,
};
// 定义了xxx设备的寄存器映射枚举,表示不同寄存器的偏移量
typedef struct SOCxxxState {
SysBusDevice parent_obj; // SOCxxxState结构体的父对象
MemoryRegion iomem; // 内存区域对象,用于访问设备的内存映射区域
qemu_irq irq; // 设备的中断请求(IRQ)线
uint32_t regs[NUM_OF_xxx_REG]; // 存储xxx设备寄存器的数组
uint32_t xxx_int_mask; // xxx设备的中断屏蔽掩码
uint64_t hva_ram_ptr; // 虚拟地址指针,指向设备的RAM地址
uint64_t gva_ram_addr; // 全局虚拟地址指针,指向设备的RAM地址
QemuThread thread; // QEMU线程对象,用于处理设备相关的线程操作
QemuMutex thr_mutex; // QEMU互斥锁,用于线程同步
QemuCond thr_cond; // QEMU条件变量,用于线程同步
QemuSemaphore hw_sem; // QEMU信号量,用于线程同步
Fifo64 addr_fifo[SOC_xxx_NUM]; // 64位FIFO队列数组,用于存储地址
} SOCxxxState;
// 定义了SOCxxxState结构体,用于表示xxx SOC设备的状态和属性
typedef struct SOCxxxClass {
SysBusDeviceClass parent_class; // SOCxxxClass结构体的父类
} SOCxxxClass;
// 定义了SOCxxxClass结构体,用于表示xxx SOC设备的类信息
(4)设备相关函数
#include <stdio.h>
#include <stdlib.h>
#include "qemu/osdep.h"
#define debug_log 0 // 调试标志位
// 用于将物理地址转换为主机虚拟地址的函数
static void *raw_gpa2hva(MemoryRegion **p_mr, hwaddr addr, Error **errp)
{
// 查找地址对应的内存区域
MemoryRegionSection mrs = memory_region_find(get_system_memory(), addr, 1);
// 检查内存区域是否为RAM或ROMD类型
if (!memory_region_is_ram(mrs.mr) && !memory_region_is_romd(mrs.mr)) {
printf("Memory at address 0x%lx is not RAM\n", addr);
memory_region_unref(mrs.mr); // 释放内存区域引用
return NULL;
}
*p_mr = mrs.mr; // 将内存区域指针传递给调用者
return qemu_map_ram_ptr(mrs.mr->ram_block, mrs.offset_within_region); // 返回主机虚拟地址
}
// 将物理地址转换为主机虚拟地址的包装函数
static uint64_t gpa2hva(hwaddr addr)
{
Error *local_err = NULL;
MemoryRegion *mr = NULL;
void *ptr;
ptr = raw_gpa2hva(&mr, addr, &local_err); // 调用原始函数
memory_region_unref(mr); // 释放内存区域引用
return (uint64_t)ptr; // 返回主机虚拟地址
}
// 初始化xxx设备的配置信息
static void SOC_ayers_xxx_init_config(
uint32_t *xxx_reg, hbsim_xxx_if *xxx_config)
{
// 初始化xxx_config结构体,将xxx设备的配置信息填充到xxx_config中
}
// 更新xxx设备的中断状态
static void SOC_ayers_xxx_update_interrupt(
SOCxxxState *xxx_state, uint32_t bit)
{
// 更新xxx设备的中断状态,并通知QEMU的中断管理系统
}
// 从文件中读取数据
static int read_file(const char *filename, char *addr, uint32_t size)
{
FILE *Fd = NULL;
Fd = fopen(filename, "r"); // 打开文件以供读取
fread(addr, size, 1, Fd); // 从文件中读取数据
fflush(Fd); // 刷新文件流以确保数据写入文件
fclose(Fd); // 关闭文件
return size; // 返回读取的数据大小
}
// 将数据写入文件
static int dumpFile(const char *filename, char *srcBuf, unsigned int size)
{
FILE *yuvFd = NULL;
yuvFd = fopen(filename, "w"); // 打开文件以供写入
fwrite(srcBuf, size, 1, yuvFd); // 将数据写入文件
fflush(yuvFd); // 刷新文件流以确保数据写入文件
fclose(yuvFd); // 关闭文件
return 0; // 返回写入结果
}
// 处理xxx设备的数据
static void hbsimxxx_process(hbsim_xxx_if xxx_config)
{
// 处理xxx设备的数据(占位函数,具体实现可能在其他地方)
}
// 处理xxx设备的数据并更新中断状态
static void SOC_ayers_xxx_process(SOCxxxState *xxx_state)
{
hbsim_xxx_if xxx_config;
SOC_ayers_xxx_init_config(xxx_state->regs, &xxx_config); // 初始化配置信息
hbsimxxx_process(xxx_config); // 处理xxx设备的数据
}
// xxx设备的处理线程函数
static void *SOC_ayers_xxx_process_thread(void *param)
{
SOCxxxState *xxx_state = (SOCxxxState *)param;
while (1) {
qemu_sem_wait(&xxx_state->hw_sem); // 等待信号量
SOC_ayers_xxx_process(xxx_state); // 处理xxx设备的数据
SOC_ayers_xxx_update_interrupt(xxx_state, 1); // 更新中断状态
}
return NULL;
}
// 读取xxx设备的寄存器值
static uint64_t SOC_ayers_xxx_read(void *opaque, hwaddr offset, unsigned size)
{
SOCxxxState *xxx_state = (SOCxxxState *)opaque;
uint32_t index = offset >> 2; // 计算寄存器索引
uint64_t value = xxx_state->regs[index]; // 从寄存器数组中读取值
switch (index) {
case xxx_INT_STATUS:
qemu_set_irq(xxx_state->irq, 0); // 清除中断状态并通知QEMU
break;
default:
break;
}
return value; // 返回读取的寄存器值
}
// 写入xxx设备的寄存器值
static void SOC_ayers_xxx_write(
void *opaque, hwaddr offset, uint64_t value, unsigned size)
{
SOCxxxState *xxx_state = (SOCxxxState *)opaque;
uint32_t index = offset >> 2; // 计算寄存器索引
xxx_state->regs[index] = value; // 将值写入寄存器
switch (index) {
case xxx_PROCESS_CONFIG:
if (xxx_state->regs[index] & xxx_DDR_START) {
xxx_state->regs[index] = 0;
qemu_sem_post(&xxx_state->hw_sem); // 发送信号以启动处理线程
}
break;
case xxx_INT_STATUS:
xxx_state->regs[index] &= ~value; // 清除特定位的中断状态
break;
default:
break;
}
}
// 定义设备的内存操作函数集合
static const MemoryRegionOps SOC_ayers_xxx_ops = {
.read = SOC_ayers_xxx_read, // 读取函数
.write = SOC_ayers_xxx_write, // 写入函数
.endianness = DEVICE_NATIVE_ENDIAN, // 设备的字节序
};
// 初始化设备的寄存器
static void SOC_ayers_xxx_init_regs(SOCxxxState *xxx_state)
{
xxx_state->regs[xxx_INT_MASK] = 0; // 初始化寄存器中断掩码
return;
}
// 初始化设备实例
static void SOC_ayers_xxx_instance_init(Object *obj)
{
SOCxxxState *xxx_state = SOC_xxx_OBJECT(obj);
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
// 初始化设备内存区域
memory_region_init_io(&xxx_state->iomem, obj, &SOC_ayers_xxx_ops, sbd,
TYPE_SOC_xxx, 0x1000);
sysbus_init_mmio(sbd, &xxx_state->iomem); // 初始化设备的MMIO接口
sysbus_init_irq(sbd, &xxx_state->irq); // 初始化设备的IRQ接口
SOC_ayers_xxx_init_regs(xxx_state); // 初始化设备的寄存器
qemu_sem_init(&xxx_state->hw_sem, 0); // 初始化设备的信号量
}
// 实例化设备
static void SOC_ayers_xxx_realize(DeviceState *dev, Error **errp)
{
SOCxxxState *xxx_state = SOC_xxx_OBJECT(dev);
char cmd_line[128] = {0};
int32_t ret;
qemu_mutex_init(&xxx_state->thr_mutex); // 初始化互斥锁
qemu_cond_init(&xxx_state->thr_cond); // 初始化条件变量
qemu_thread_create(&xxx_state->thread, TYPE_SOC_xxx,
SOC_ayers_xxx_process_thread, xxx_state, QEMU_THREAD_JOINABLE); // 创建设备处理线程
}
// 取消实例化设备
static void SOC_ayers_xxx_unrealize(DeviceState *dev)
{
SOCxxxState *xxx_state = SOC_xxx_OBJECT(dev);
qemu_mutex_lock(&xxx_state->thr_mutex);
qemu_mutex_unlock(&xxx_state->thr_mutex);
qemu_cond_signal(&xxx_state->thr_cond); // 发送信号以唤醒等待的线程
qemu_thread_join(&xxx_state->thread); // 等待线程退出
qemu_cond_destroy(&xxx_state->thr_cond); // 销毁条件变量
qemu_mutex_destroy(&xxx_state->thr_mutex); // 销毁互斥锁
}
// 定义设备属性列表
static Property SOC_ayers_xxx_properties[] = {
DEFINE_PROP_UINT64("hva_ram_ptr", SOCxxxState, hva_ram_ptr, 0),
DEFINE_PROP_UINT64("gva_ram_addr", SOCxxxState, gva_ram_addr, 0),
DEFINE_PROP_END_OF_LIST(),
};
// 初始化设备类
static void SOC_ayers_xxx_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = SOC_ayers_xxx_realize; // 设备实例化函数
dc->unrealize = SOC_ayers_xxx_unrealize; // 设备取消实例化函数
device_class_set_props(dc, SOC_ayers_xxx_properties); // 设置设备属性列表
return;
}
// 定义设备类型信息
static const TypeInfo SOC_ayers_xxx_info = {
.name = TYPE_SOC_xxx, // 设备类型名称
.parent = TYPE_SYS_BUS_DEVICE, // 父类设备类型
.instance_size = sizeof(SOCxxxState), // 实例大小
.instance_init = SOC_ayers_xxx_instance_init, // 实例初始化函数
.class_size = sizeof(SOCxxxClass), // 类大小
.class_init = SOC_ayers_xxx_class_init, // 类初始化函数
};
// 注册设备类型
static void SOC_ayers_xxx_register(void)
{
type_register_static(&SOC_ayers_xxx_info); // 注册设备类型信息
}
type_init(SOC_ayers_xxx_register); // 初始化设备类型