QEMU ARM semihosting

本文介绍如何利用QEMU在ARM架构上实现半主机功能,通过创建简单的裸机程序测试其功能,包括标准输入输出和文件系统访问,并详细解释了链接脚本的修改、编译命令及底层执行过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

QEMU is able to emulate ARM architectures with many details. One thing that the qemu-system-armprogram implements is the Angel interface, that enables semihosting. Semihosting involves two machines: a target (the embedded device), and a host (such as a PC) that is connected to the target through a debug interface. An embedded program running in semihosted mode is executing on the target architecture, but is able to see some resources of the host machine.

I created a simple bare metal program to test the semihosting functionality. The C code of the program is the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdio.h>
void main() {
  FILE *fp;
  char line[100];
  printf ( "Hello World!\n" );
  fp = fopen ( "log.txt" , "w" );
  if (fp == NULL) return ;
  while ( fgets (line, 100, stdin) != NULL) {
  fprintf (fp, "%s" , line);
  if (line[0] == 'q' ) break ;
  }
  close(fp);
}

The purpose is to try to access the standard output, standard input and filesystem of the host. To compile this example on my Linux machine I used the toolchain Sourcery G++ Lite 2010q1-188, that comes with a series of libraries and linker scripts that allow to create programs running in a hosted environment. In my case (depending on the installation path) the directory “~/CodeSourcery/Sourcery_G++_Lite/arm-none-eabi/lib/” contains the linker script “generic-hosted.ld” that is almost OK to use: it needs just a little change in the memory description because of QEMU behavior.

I copied “generic-hosted.ld” into a local file that I called “qemu-hosted.ld” and then I opened to modify it. The problem is that QEMU loads the program binary into address 0x10000, but the linker script assumes that the program is executed at address 0x0. I decided to change the memory section of the script to tell the linker that the memory starts at 0x10000; in practice I changed the following lines:

1
2
3
4
MEMORY
{
  ram (rwx) : ORIGIN = 0x0, LENGTH = 128M
}

…into these:

1
2
3
4
MEMORY
  {
  ram (rwx) : ORIGIN = 0x10000, LENGTH = 127M
  }

To compile the program and run it inside QEMU the commands are (assuming the C source file has been called “main.c“):

1
2
3
$ arm-none-eabi-gcc   -T qemu-hosted.ld main.c -o main.elf
$ arm-none-eabi-objcopy -O binary main.elf main.bin
$ qemu-system-arm -semihosting -kernel main.bin

The terminal will display the “Hello World!” line and then accept user input. The input is written inside the file “log.txt” and when the standard input is closed (using CTRL-D) or the line starts with the character ‘q‘ the program ends. To start QEMU without the graphic window, use the following command:

1
$ qemu-system-arm -nographic -monitor null -serial null -semihosting -kernel main.bin

The “-monitor null -serial null” options are necessary to avoid conflicts on the standard streams.

What happens underneath this emulation? To discover it, it’s interesting to watch the assembly code that is run. The following command disassembles the program into the file main.code:

1
$ arm-none-eabi-objdump -d main.elf > main.code

Examining the code, it can be traced that the main function calls fopen, which eventually calls a low-level function called _open, that contains a SuperVisor Call (SVC) instruction.

1
2
3
4
5
00013a9c <_open>:
  [...]
  13b18:    e3a00001     mov    r0, #1
  13b1c:    ef123456     svc    0x00123456
  [...]

The SVC instruction, when using 0x123456 as parameter, tells QEMU to use its implementation of the Angel interface. The r0 register contains the code of the function to emulate, according to this table. Other registers can be used as other parameters to pass, like a function call.

The semihosting functionality is useful in prototyping, especially to emulate some parts of the systems to speed up development; but the possibilities are various. For example:

  • when data coming from a sensor is difficult to control, it can be emulated by getting data from a file on the host machine instead.
  • the program can dump intermediate data to file, without problems of non-volatile memory space.
  • the embedded device can get/send data with the Internet through the host PC.


转自:http://balau82.wordpress.com/2010/11/04/qemu-arm-semihosting/
### QEMU ARM 模拟使用指南 #### 启动简单 QEMU Arm 实例 为了启动一个基本的 QEMU Arm 环境,命令行指令如下所示[^1]: ```bash ~/local/xPacks/qemu-arm/<version>/bin/qemu-system-arm \ -machine versatilepb \ -cpu cortex-a9 \ -nographic \ -kernel vmlinuz-<your-linux-kernel> ``` 此设置利用 `versatilepb` 平台模型来创建基于 Cortex-A9 CPU 的虚拟化环境。 `-nographic` 参数用于禁用图形输出以便于简化控制台交互。 #### 准备工作与安装过程 对于希望在 QEMU 中安装并运行 ARM 架构的操作系统而言,准备阶段至关重要。这通常涉及获取适合目标平台的 ISO 或者磁盘映像文件,并确保拥有正确的 QEMU 版本和支持库[^3]。 #### 推荐工具:xPack QEMU Arm 考虑到易用性和功能性,xPack QEMU Arm 是一种优秀的二进制分发版本,它能够提供稳定可靠的 ARM 仿真体验。该项目托管在一个公开仓库上,方便开发者下载和贡献改进[^2]. #### 教学应用案例 教育领域内的应用场景十分广泛;比如,在教授计算机组成原理课程时,教师可以通过 xPack QEMU Arm 来演示 ARM 处理器内部的工作流程及其同操作系统之间的互动方式。 #### Windows 下的具体实现例子 具体到 Windows 操作环境下,有专门针对该平台优化过的指导文档介绍了如何部署 Kylin OS 这样的 Linux 发行版至 QEMU 创建出来的 ARM 虚拟环境中去[^4]。 ```python # Python 示例代码仅作展示用途而非实际功能实现部分 print("This is an example code block.") ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值