玩转QEMU硬件模拟器 - Versatilepb模拟器开发概述
Versatilepb模拟器源码
前段时间作者基于qemu-8.2.5成功开发了基于Cortex-M0plus内核的传感器硬件模拟器,并成功基于该硬件模拟器实现了全功能固件的开发与调试,目前项目已经量产。从而通过具体的项目验证了qemu模拟器在项目开发中的巨大好处和优势。这篇博文,我们继续一起讨论一下Versatilepb模拟器是如何开发出来的。首先,读者在路径: qemu-8.2.5/hw/arm/versatilepb.c可以打开该SoC的顶层源码。作者个人觉得写的稍微有些“多,乱”,为什么呢?因为在versatilepb.c文件中除实现了SIC, PIC等外设外,同时,还实现了versatileab,versatilepb两种基于ARM内核SoC开发板的定义,作者还是倾向于分开实现,并且是*.c/.h*模块化实现。当然了,如果读者已经很熟悉qemu的模拟范式和提供的api接口函数使用那就无所谓了。
熟悉了qemu的模拟范式和提供的api接口函数使用以后,那versatilepb模拟器是如何添加外设的呢?这就要先从Arm官网下载用户手册了Versatile Application Baseboard for ARM926EJ-S User Guide,在4.1 Memory map部分,读者可以看到各个外设的地址空间是如何分配的。事实上,QEMU也是按照这里的User Guide来开发Versatilepb模拟器的。
Versatilepb外设实现
versatilepb.c中的static void versatile_init(*MachineState machine, int board_id)是核心外设实现函数。涉及到外设的创建、初始化、总线系统地址空间映射、连接中断信号、外设属性设置、连接到系统总线等系列操作。QEMU模拟器实现的逻辑比较清晰,遵从自底向上原则,先实现外设模拟,再将模拟的外设连接到总线上,从而构成一个具有特定SoC功能的用C语言实现的硬件模拟器。这点我们可以软件的角度从versatilepb.c的头文件内容清晰的看到这种实现方式。
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "cpu.h"
#include "hw/sysbus.h"
#include "migration/vmstate.h"
#include "hw/arm/boot.h"
#include "hw/net/smc91c111.h"
#include "net/net.h"
#include "sysemu/sysemu.h"
#include "hw/pci/pci.h"
#include "hw/i2c/i2c.h"
#include "hw/i2c/arm_sbcon_i2c.h"
#include "hw/irq.h"
#include "hw/boards.h"
#include "hw/block/flash.h"
#include "qemu/error-report.h"
#include "hw/char/pl011.h"
#include "hw/sd/sd.h"
#include "qom/object.h"
#include "audio/audio.h"
从软件编程的角度看,versatilepb.c将实现net, pci, i2c, irq, flash, char, audio等外设设备功能的模块头文件都包含了进来,而这些外设的实现同样遵从范式创建。各外设的具体实现代码读者可以跳转到qemu-8.2.5/hw/去查看,这里,我们以versatilepb.c中的Secondary Interrupt Controller(SIC) 外设实现为例简要介绍:
#define TYPE_VERSATILE_PB_SIC "versatilepb_sic"
OBJECT_DECLARE_SIMPLE_TYPE(vpb_sic_state, VERSATILE_PB_SIC)struct vpb_sic_state {SysBusDevice parent_obj;MemoryRegion iomem;uint32_t level;uint32_t mask;uint32_t pic_enable;qemu_irq parent[32];int irq;
};static const VMStateDescription vmstate_vpb_sic = {.name = "versatilepb_sic"