如何在没有用户干预的情况下执行裸机程序后干净退出 QEMU?

How to cleanly exit QEMU after executing bare metal program without user intervention?

我正在为 ARM 系统组装一个交叉编译单元测试平台,并 运行使用 qemu-system-arm 在主机上进行测试。具体来说,我使用 qemu 来模拟 Stellaris LM3S6965 评估板,因为它包含一个 Cortex M3 处理器,就像我的目标环境一样。 qemu 中的二进制 运行 是使用 GNU Tools for ARM 构建的。

不涉及OS。测试套件是 运行 作为裸机应用程序,在 -nographic 模式下使用 qemu。工具链和测试平台本身运行良好。并且测试成功 运行 完成并在 qemu 中生成测试结果也很好。

问题在于将 qemu 包装在自动构建工具中(在本例中为 Rake)。除了键盘命令之外,我还没有找到让 qemu 在测试套件 运行s 后退出并吐出结果的好方法。这会导致构建环境挂起/依赖用户干预。

我四处寻找,没有找到关于如何在程序终止后完成简单退出的好资源。我确实找到了 运行ning qemu 和 -no-reboot 选项的一些建议,然后从模拟器中的程序 运行ning 触发系统重置。我试过这个。它有效……有点。在 main() 执行后,我将适当的值写入仿真处理器的重置向量,这确实会触发重置。 运行 测试套件 qemu 报告捕捉到系统重置后。但是,它将此报告为硬件错误,转储寄存器内容,然后愤怒地退出(下面的错误消息)。虽然这确实在测试套件 运行s 之后完成了退出,但由于 qemu 以错误条件退出,它会破坏自动构建脚本。

qemu: hardware error: System reset

我想避免将键盘命令插入到构建中以模拟用户干预。我也想避免依赖 qemu 以错误状态退出。

看来我离干净的出口很近了,但还差得远。搜索 qemu 错误消息(上图)除了相关的错误报告外没有产生任何相关文档。

在我缺少的裸机程序中,是否存在导致 qemu 在 main() returns 之后退出的机制?这个 -no-reboot + 系统重置策略会起作用吗?如果是这样,还需要什么才能让 qemu 干净地退出?

通常你需要在硬件上做任何会导致系统关闭(断电)的事情; QEMU 将使它执行'exit QEMU'。不幸的是,并非我们模拟的所有硬件都实现了断电机制(有时它没有连接到 QEMU 模型中,尽管这通常是一个容易修复的错误)。

对我来说最干净的选择是获取与我们已经使用的版本接近的 Qemu 稳定版本的源代码。以下引用Qemu源码1.1.2版本

我在 armv7m_nvic.c 中修改了 Cortex M3 + Stellaris LM3S6965 评估板的复位向量处理仿真。我用 qemu_system_reset_request() 调用替换了 hw_error() 调用。这个内部系统调用将重置虚拟机,但也会响应 -no-reboot 命令行选项以进行干净关闭,如我最初的问题中所讨论的那样。

这些build instructions worked for me after grabbing a snapshot of Qemu 1.1.2。我遇到了几个构建错误,但网络搜索很快解决了每个问题。

我建议为 ARM 处理器使用 Angel 接口。对调试很有帮助。您可以在 ARM Info Center 上阅读有关它的内容。特别是查看操作 angel_SWIreason_ReportException (0x18) 和参数 ADP_Stopped_ApplicationExit,QEMU 将了解您的应用程序已结束。

不要忘记 运行 QEMU 带有 -semihosting 参数,像这样:

qemu-system-arm -nographic -semihosting -kernel your_binary

这里是告诉 QEMU 停止的代码(你必须使用一些汇编程序):

register int reg0 asm("r0");
register int reg1 asm("r1");

reg0 = 0x18;    // angel_SWIreason_ReportException
reg1 = 0x20026; // ADP_Stopped_ApplicationExit

asm("svc 0x00123456");  // make semihosting call

你也可以在 github 我使用它的地方查看我的项目。

aarch64 半主机退出

给了A32,这里是A64:

.global main
main:
    /* 0x20026 == ADP_Stopped_ApplicationExit */
    mov x1, #0x26
    movk x1, #2, lsl #16
    str x1, [sp,#0]

    /* Exit status code. Host QEMU process exits with that status. */
    mov x0, #0
    str x0, [sp,#8]

    /* x1 contains the address of parameter block.
     * Any memory address could be used. */
    mov x1, sp

    /* SYS_EXIT */
    mov w0, #0x18

    /* Do the semihosting call on A64. */
    hlt 0xf000

这是 GitHub 上的示例:

文档已移至:https://developer.arm.com/docs/100863/latest

当前的 ARMv7M qEmu(基于 TI Stellaris LM3S6965 微控制器)支持从 AICRCR 寄存器(Application Interrupt and Reset Control Register)重置。 写入此寄存器的 SYSRESETREQ 位会向外部系统发出请求复位的信号。

写入AICRCR需要将0x5FA写入VECTKEY字段,否则处理器忽略写入。

此行使 ARMv7M qEmu 重置。

SCB->AIRCR = (0x5FA << SCB_AIRCR_VECTKEY_Pos) | SCB_AIRCR_SYSRESETREQ_Msk;

要防止 qEmu 无限重启,您可以添加 qEmu 参数 -no-reboot

正在关注 ,it worked using different assembly, and i was working with zephyr qemu cortex m3

static inline void _exit_qemu() {
  register u32_t r0 __asm__("r0");
  r0 = 0x18;
  register u32_t r1 __asm__("r1");
  r1 = 0x20026;
  __asm__ volatile("bkpt #0xAB");
}

qemu-system-arm -cpu cortex-m3 -machine lm3s6965evb -nographic -vga none -net none -pidfile qemu.pid -serial mon:stdio -semihosting -kernel build/zephyr/zephyr.elf