我很想深入研究 ARM 的 TrustZone,想要搭建一个可以模拟和调试 Trusted Application 的平台环境。我了解到 Open-TEE (ATF) 项目提供有一个 QEMU 模拟调试环境。虽然是针对于 Open-TEE 的 TrustZone 实现,但是也可以作为一个参考来学习。在阅读这个项目的代码时,我留意到了一个 QEMU 的启动参数:
经过一番查找后发现这个 Semihosting 功能颇有用处:他能够让 bare-metal 的 ARM 设备通过拦截指定的 SVC 指令,在连操作系统都没有的环境中实现 POSIX 中的许多标准函数,比如 printf、scanf、open、read、write 等等。这些 IO 操作将被 Semihosting 协议转发到 Host 主机上,然后由主机代为执行,所以在 ARM 模拟器中执行一个 printf 可以直接打印到 Host 主机上的终端窗口中;在 ARM 模拟器中写一个文件可以直接写到 Host 主机的当前目录下,等等。
如果要写一个 TrustZone Kernel 的 QEMU 模拟环境,如果使用了 Semihosting,则不需要去模拟 FLASH 存储设备就能直接从 Host 主机上加载文件;不需要模拟串口设备就能直接打印 Log 输出,将会大大减少开发工作量。Open-TEE 项目也正是利用了 Semihosting 非常简单地就加载了 Trusted Application。
为了今后能够在我自己的项目中使用 Semihosting 这一方便的功能,我想要写点 Hello World 程序看看如何使用这个功能。
Semihosting 其实是 ARM 官方定义的功能,所有 ARM 芯片都支持这个协议,只要连上硬件调试器就能使用。当然了,QEMU 模拟 ARM 也把 Semihosting 模拟了一遍,只不过不需要什么特殊的连接就能直接使用。这个是 ARM 的官方文档:
https://developer.arm.com/documentation/dui0471/g/Semihosting/The-semihosting-interface
可以看到 SVC 0x123456 是官方给 Semihosting 预留的指定命令。当这条 SVC 被执行时,R0 寄存器的值是一个 Operation ID,R1 寄存器的值是指向附加参数结构体的指针。这个页面列举了 Semihosting 支持的 Operations:
https://developer.arm.com/documentation/dui0471/g/Semihosting/Semihosting-operations
比方说最简单的 puts 函数,对应的 Operation ID 是 SYS_WRITE0 (0x04),那我们就可以很简单地用 C 和汇编写一个 Hello World:
https://github.com/iNvEr7/qemu-learn/blob/master/semihosting
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)