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

时间:2015-08-13 14:04:51

标签: unit-testing arm qemu bare-metal

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

没有涉及操作系统。测试套件作为裸机应用程序运行,qemu处于-nographic模式。工具链和测试台本身工作正常。测试成功完成并在qemu内生成测试结果也很好。

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

我看起来很高,并且没有找到关于如何在程序终止后完成简单退出的好资料。我确实找到了一些使用-no-reboot选项运行qemu的建议,然后从模拟器中运行的程序触发系统重置。我试过这个。它有效......有点儿。在main()执行后,我将适当的值写入模拟处理器的复位向量,这确实触发了复位。运行测试套件后qemu报告系统重置。但是,它将此报告为硬件错误,转储寄存器内容,然后退出生气(下面的错误消息)。虽然这确实在测试套件运行后完成退出,然后由于qemu退出并出现错误条件,它会破坏自动构建脚本。

qemu: hardware error: System reset

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

我似乎接近一个干净的出口,但不是那里。搜索qemu错误消息(上面)除了相关的错误报告之外没有产生相关文档。

是否有一种机制可以在{I} {}返回我错过的裸机程序后导致qemu退出?这个main() +系统重置策略是否有效?如果是这样,还有什么必要让qemu干净利落地退出?

6 个答案:

答案 0 :(得分:5)

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

不要忘记使用-semihosting参数运行QEMU,如下所示:

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查看我的项目。

答案 1 :(得分:1)

通常,您需要在硬件上执行任何操作都会导致系统关闭(断电); QEMU将做出“退出QEMU”。遗憾的是,并非所有我们模拟的硬件都实现了断电机制(有时它并没有在QEMU模型中连接,尽管这通常是一个容易修复的错误)。

答案 2 :(得分:1)

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

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

抓住build instructions后,这些a snapshot of Qemu 1.1.2对我有用。我遇到了几个构建错误,但网络搜索很快解决了每个问题。

答案 3 :(得分:0)

aarch64半主机退出

https://stackoverflow.com/a/40957928/895245给了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

答案 4 :(得分:0)

当前的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

答案 5 :(得分:0)

J. Havran answer之后,它使用了不同的程序集,而我正在使用zephyr qemu cortex m3

In [463]: df.groupby('p').agg(sum).reset_index()
Out[463]: 
   p  c1  c2  c3
0  A   1   1   1
1  B   1   0   1

`import 'package:flutter/material.dart';
class FeedPage extends StatefulWidget {
  @override
  _feedPageState createState() => new _feedPageState();
}
class _feedPageState extends State<FeedPage> {

  @override
  Widget build(BuildContext context) {
    return new FlatButton(
      onPressed: () {
        setState(() {
          //change the currentPage in RootPage so it switches FeedPage away and gets a new class that I'll make
        });
      },
      child: new Text('Go to a new page but keep root, just replace this feed part'),
    );
  }
}`