在QEMU中定制AST2600设备:从Machine定义到硬件模拟实战

张开发
2026/4/29 5:21:08 15 分钟阅读

分享文章

在QEMU中定制AST2600设备:从Machine定义到硬件模拟实战
1. 理解AST2600与QEMU模拟基础AST2600是Aspeed公司推出的高性能SoC芯片广泛应用于服务器管理、工业控制等领域。它集成了双核Cortex-A7处理器、丰富的外设接口和硬件加速引擎。在实际开发中我们经常需要在QEMU中模拟AST2600的特定硬件配置以便进行固件开发和测试。QEMU作为开源的硬件模拟器允许我们创建虚拟的Machine类型来模拟特定硬件平台。与物理开发板相比QEMU模拟具有以下优势快速迭代无需等待硬件随时修改配置调试方便可以设置断点、单步执行成本低廉不需要购买多套硬件设备在开始定制之前建议先熟悉QEMU的基本架构。QEMU通过Machine类型来描述整个硬件平台每个Machine包含CPU、内存、外设等组件。对于AST2600QEMU已经提供了基础的ast2600-evb Machine类型我们可以基于它进行扩展。2. 创建自定义Machine类型2.1 修改aspeed.c文件首先需要在QEMU源码的hw/arm/aspeed.c文件中添加新的Machine类型。这里我们以创建一个名为pf12的Machine为例static const TypeInfo aspeed_machine_types[] { // ...其他Machine定义... { .name MACHINE_TYPE_NAME(ast2600-evb), .parent TYPE_ASPEED_MACHINE, .class_init aspeed_machine_ast2600_evb_class_init, }, { .name MACHINE_TYPE_NAME(pf12), .parent TYPE_ASPEED_MACHINE, .class_init aspeed_machine_pf12_class_init, }, // ...其他Machine定义... };这段代码在QEMU的类型系统中注册了一个新的Machine类型pf12它继承自ASPEED_MACHINE基类并使用aspeed_machine_pf12_class_init函数进行初始化。2.2 实现Machine类初始化函数接下来需要实现aspeed_machine_pf12_class_init函数这个函数定义了Machine的各种属性static void aspeed_machine_pf12_class_init(ObjectClass *oc, void *data) { MachineClass *mc MACHINE_CLASS(oc); AspeedMachineClass *amc ASPEED_MACHINE_CLASS(oc); mc-desc Aspeed AST2600 EVB (Cortex-A7); amc-soc_name ast2600-a3; amc-hw_strap1 AST2600_EVB_HW_STRAP1; amc-hw_strap2 AST2600_EVB_HW_STRAP2|0xC800; // 启用ABR功能 amc-fmc_model mx66u51235f; amc-spi_model mx66u51235f; amc-num_cs 2; amc-macs_mask ASPEED_MAC0_ON | ASPEED_MAC1_ON | ASPEED_MAC2_ON | ASPEED_MAC3_ON; amc-i2c_init pf12_i2c_init; // 自定义I2C设备初始化 mc-default_ram_size 1 * GiB; mc-default_cpus mc-min_cpus mc-max_cpus aspeed_soc_num_cpus(amc-soc_name); mc-reset pf12_reset; // 自定义复位函数 }这个函数设置了Machine的各种参数包括SoC型号、硬件strap值、Flash型号、MAC地址启用情况等。最重要的是指定了自定义的I2C初始化函数pf12_i2c_init和复位函数pf12_reset。3. 定制I2C设备3.1 I2C设备初始化函数实现AST2600支持多个I2C总线我们需要根据实际硬件配置添加相应的I2C设备。以下是pf12_i2c_init函数的实现示例static void pf12_i2c_init(AspeedMachineState *bmc) { AspeedSoCState *soc bmc-soc; DeviceState *dev; // 添加温度传感器 i2c_slave_create_simple(aspeed_i2c_get_bus(soc-i2c, 1), TYPE_TMP105, 0x4d); // 初始化EEPROM设备 uint8_t *eeprom_buf2 g_malloc0(8 * 1024); uint8_t buf2[] {0x08, 0xbf, 0xb8, 0x0c, 0xbe, 0xac, 0x00, 0xfe}; memcpy(eeprom_buf2, buf2, sizeof(buf2)); smbus_eeprom_init_one(aspeed_i2c_get_bus(soc-i2c, 6), 0x56, eeprom_buf2); // 初始化FRU EEPROM uint8_t *eeprom_fru g_malloc0(8 * 256); uint8_t fru[] {0x01, 0x00, 0x01, 0x05, 0x0f, 0x00, 0x00, 0xea}; memcpy(eeprom_fru, fru, sizeof(fru)); smbus_eeprom_init_one(aspeed_i2c_get_bus(soc-i2c, 6), 0x54, eeprom_fru); // 添加RTC设备 i2c_slave_create_simple(aspeed_i2c_get_bus(soc-i2c, 2), TYPE_DS1338, 0x10); // 添加更多温度传感器 i2c_slave_create_simple(aspeed_i2c_get_bus(soc-i2c, 7), TYPE_TMP105, 0x49); i2c_slave_create_simple(aspeed_i2c_get_bus(soc-i2c, 8), TYPE_TMP105, 0x4B); }这个函数主要做了以下几件事在I2C总线1上添加了一个TMP105温度传感器初始化了两个EEPROM设备分别存储MAC地址和FRU信息在I2C总线2上添加了DS1338 RTC芯片在其他I2C总线上添加了更多温度传感器3.2 设备数据初始化技巧在实际项目中EEPROM等设备通常需要预置数据。我们可以通过以下方式处理静态数据初始化像上面示例那样直接在代码中定义静态数据从文件加载可以读取外部文件来初始化设备数据运行时动态修改通过QEMU monitor或QMP接口在运行时修改设备数据对于复杂的设备数据建议使用外部文件加载的方式这样可以在不重新编译QEMU的情况下更新设备数据。4. 实现自定义复位逻辑4.1 复位函数实现AST2600的复位逻辑可能需要根据具体硬件进行调整。以下是pf12_reset函数的实现示例static void pf12_reset(MachineState *state, ShutdownCause reason) { AspeedMachineState *bmc ASPEED_MACHINE(state); AspeedGPIOState *gpio bmc-soc.gpio; // 调用默认复位函数 qemu_devices_reset(reason); /* 设置板卡ID */ object_property_set_bool(OBJECT(gpio), gpioV4, true, error_fatal); object_property_set_bool(OBJECT(gpio), gpioV5, true, error_fatal); object_property_set_bool(OBJECT(gpio), gpioV6, true, error_fatal); object_property_set_bool(OBJECT(gpio), gpioV7, false, error_fatal); /* 设置槽位存在信号低电平有效 */ object_property_set_bool(OBJECT(gpio), gpioH4, false, error_fatal); object_property_set_bool(OBJECT(gpio), gpioH5, true, error_fatal); object_property_set_bool(OBJECT(gpio), gpioH6, true, error_fatal); object_property_set_bool(OBJECT(gpio), gpioH7, true, error_fatal); }这个复位函数主要做了两件事调用默认的复位函数qemu_devices_reset完成基础复位设置特定的GPIO状态模拟实际硬件上电时的GPIO配置4.2 复位时的注意事项在实现自定义复位逻辑时需要注意以下几点复位顺序确保先调用默认复位函数再执行自定义逻辑错误处理使用error_fatal确保配置失败时能够及时发现状态一致性确保复位后的状态与实际硬件一致调试输出可以添加调试打印方便排查复位相关问题5. 运行时参数配置5.1 Machine参数支持AST2600 Machine支持多种运行时参数配置这为测试不同硬件配置提供了便利。相关代码通常在aspeed_machine_class_props_init函数中实现static void aspeed_machine_class_props_init(ObjectClass *oc) { object_class_property_add_bool(oc, execute-in-place, aspeed_get_mmio_exec, aspeed_set_mmio_exec); object_class_property_set_description(oc, execute-in-place, boot directly from CE0 flash device); object_class_property_add_str(oc, bmc-console, aspeed_get_bmc_console, aspeed_set_bmc_console); object_class_property_set_description(oc, bmc-console, Change the default UART to \uartX\); object_class_property_add_str(oc, fmc-model, aspeed_get_fmc_model, aspeed_set_fmc_model); object_class_property_set_description(oc, fmc-model, Change the FMC Flash model); object_class_property_add_str(oc, spi-model, aspeed_get_spi_model, aspeed_set_spi_model); object_class_property_set_description(oc, spi-model, Change the SPI Flash model); }这些参数允许我们在启动QEMU时动态配置execute-in-place设置是否从Flash直接执行bmc-console指定控制台使用的UARTfmc-model和spi-model指定Flash芯片型号5.2 使用示例启动QEMU时可以这样使用这些参数qemu-system-arm -M ast2600-evb \ -drive file./flash.img,formatraw,ifmtd \ -nographic \ -serial mon:stdio \ -global driverast2600.evb,propertyexecute-in-place,valueon \ -global driverast2600.evb,propertyfmc-model,valuemx66u51235f这种灵活的配置方式使得我们可以轻松测试不同的硬件配置而无需重新编译QEMU。6. 调试技巧与常见问题在实际开发中调试是不可避免的。以下是一些实用的调试技巧QEMU监控器使用-monitor stdio参数启动QEMU可以进入监控器查看设备状态GDB调试使用-s -S参数启动QEMU然后通过GDB连接进行调试设备树查看在U-Boot中使用fdt print命令查看设备树信息日志输出在关键函数中添加printf或使用QEMU的日志系统常见问题包括设备未正确初始化检查设备初始化函数是否被调用中断不工作检查中断控制器配置和中断号是否正确内存映射错误检查设备的内存区域是否与其他设备冲突时序问题适当添加延迟或调整设备响应时间在开发过程中建议逐步添加设备功能每添加一个功能就进行测试这样可以快速定位问题。

更多文章