什么是Semihosting(半主机)- ARM处理器与主机之间IO通信机制

Semihosting简介

Semihosting是一种在Arm处理器上运行的应用程序与调试器的主机进行通信的技术。通过这个机制,跑在ARM处理器上的应用程序可以使用主机的IO设备,比如键盘输入,屏幕输出以及文件的IO等等。如果目标平台(目标开发板)没有这些IO设备,或者为了使用print()函数输出一些debug信息,那将非常有用。

  • 在AArch32模式下,应用程序通过使用 SVC(SWI)指令并携带一个特定的 SVC number,来触发一个异常,从而实现一个semihosting 请求。操作的类型是通过在通用寄存器R0,R1中传递参数确定的。在ARMv7中,优先使用 SVC指令,早期称为SWI。但是在ARMv6-M 或者 ARMv7-M, 比如 Cortex™-M1 或Cortex-M3 ,它们使用 BKPT指令来产生 semihosting请求。
  • 在AArch64模式下,应用程序使用 HLT 指令,并携带一个常数来创建一个semihosting 请求,但是它不会产生异常

正常情况下,ARM RealView编译器中的C 库函数,比如printf()和scanf()将会触发semihosting 请求。应用程序也可以通过键盘输入、屏幕输出以及文件IO来触发semihosting。详细描述可以参考文档:RealView Compilation Tools Developer Guide
使用SVC产生异常来调用semihosting
上图是使用SVC指令实现目标板与主机进行pirntf()打印显示的示例:

  1. 应用程序调用printf函数
  2. printf函数里使用SVC指令触发异常
  3. 异常被调试器处理
  4. 调试器与主机进行通信
  5. 主机屏幕上显示hello打印

总之,semihosting请求有两种方式创建:

  • 使用SVC(SWI) 或者BKPT指令
  • 使用HLT指令
    与主机上的I/O工具连接的调试器会处理这两种方式产生的请求,并开始与主机进行通信。
    下面以Trace32调试器为例,详细介绍32和64模式下的semihosting。

在大多数情况下,semihosting请求是由库函数唤醒,应用程序也可以直接唤醒semihosting请求。ARM A系列和R系列都支持A64, A32, 以及T32指令集,对于M系列,只使用T32指令集。
semihosting的操作请求是通过 trap 指令:SVC, HLT, or BKPT来实现的,关于exception,trap以及interrupt的区别,如下:

  • 异常 Exception , An unusual internal event caused by program during execution 程序在执行过程中引起的异常内部事件。比如页错误page fault, 算术溢出arithmetic underflow

  • 中断 Interrupt , An external event outside of running program。在正在运行的程序之外的事件。

  • 陷阱Trap ,Forced transfer of control to supervisor caused by exception or interrupt,Not all exceptions cause
    traps,由于异常和中断,强制将控制权转移给supervisor,并不是所有的异常都会导致traps。
    Semihosting Trap指令以及编码总结如下:

ProfileInstruction SetInstructionOpcode
A+R ProfileA64HLT #0xF0000xD45E0000
A32SVC #0x1234560xEF123456
A32HLT #0xF0000xE10F0070
T32SVC #0xAB0xDFAB
T32HLT #0x3C0xBABC
M–ProfileT32BKPT #0xAB0xBEAB

对于A32和T32的A系列以及R系列而言,可以使用SVC指令和HLT指令,Semihosting的实现必须支持ARM架构中该指令的所有版本。尽管HLT指令在ARMv8中被定义,但是在ARMv7以及更早的版本中也可以使用,当然,这可能需要semihosting agent把它当作 UNDEF 异常来处理。

AArch64 HLT Emulation Mode

使用 HLT 指令可以将 处理器停止,并且不需要设置额外的断点。为了触发semihosting请求,HLT指令需要带一个 0xF000 的立即数,在semihosting需要传递的数据被处理完后,调试器将重启处理器。
在Trace32中,这个模式通过指令TERM.METHOD ARMSWI [<address>]来使能,并且在 TERM.GATE窗口上显示semihosting的屏幕输出。此外,只有当 TERM.GATE窗口存在,对semihosting请求的处理才会生效。
TERM.HEAPINFO 定义了系统的堆栈位置,C库通过SYS_HEAPINFO semihosting 请求来读取内存信息,并且用它们来做初始化。
在**~~/demo/arm/etc/semihosting_arm_emulation/armv8_aarch64/halt_armv8.cmm**中可以找到AArch64的使用示例。
下图为AArch64模式下的semihosting示意图,左边为target,目标板,右边为PC主机,中间的为调试器。调试器与目标板通过JTAG连接,目标主机通过USB或者以太网接口与调试器连接。Trace32程序在主机上运行,主机上还有显示器键盘以及文件系统等IO设备。
在这里插入图片描述

AArch64 DCC Communication Mode (DCC = Debug Communication Channel)

在AArch64下,用户不能为semihosting使用Arm 库,因为HLT指令将会是处理器停止工作。因此处理DCC通信的异常处理器也不会被执行。
在semihosting的Arm 库不能被使用的情况下,用户可以替代性地对semihosting请求使用原生的Trace32格式。并且并不需要SWI处理器(在t32swi.c中),用户可以通过DCC直接发送请求。
在Trace32中,这个模式通过指令TERM.METHOD DCC3来使能,并且在 TERM.GATE窗口上显示semihosting的屏幕输出。此外,只有当 TERM.GATE窗口存在,对semihosting请求的处理才会生效。 TERM.HEAPINFO 定义了系统的堆栈位置,C库通过SYS_HEAPINFO semihosting 请求来读取内存信息,并且用它们来做初始化。
示例程序见 ~~/demo/arm/etc/semihosting_trace32_dcc
在这里插入图片描述

AArch32 SVC(SWI)Emulation Mode

SVC异常将会将程序停止,一个断点将会在SVC异常入口处产生。当程序停止时,调试器开始处理semihosting请求,并提供与主机必要的通信接口,在SVC异常调用时,会将当前PC寄存器中的地址存储到ELR寄存器中,当调试器重启应用程序时,便从ELR中获取地址。其他比如DCC模式,SVC的参数需为0x123456,来表明这是个semihosting 请求。
在Trace32中,这个模式通过指令TERM.METHOD ARMSWI [<address>]来使能,并且在 TERM.GATE窗口上显示semihosting的屏幕输出。此外,只有当 TERM.GATE窗口存在,对semihosting请求的处理才会生效。
TERM.HEAPINFO 定义了系统的堆栈位置,C库通过SYS_HEAPINFO semihosting 请求来读取内存信息,并且用它们来做初始化。
当使用TERM.METHOD ARMSWI [<address>],任何有断点的内存位置都可以用作semihosting 服务入口,而不是SVC调用。应用程序只需要跳转到那个位置。在为请求提供服务之后,程序继续在该地址执行,不是在链接寄存器ELR中的地址。例如可以在该地址放置一个ERET命令,并在ELR中提交返回地址。由于此方法不使用SVC命令,没有参数(0x123456)将被检查以识别semihosting。
An example for AArch32 can be found in:~~/demo/arm/etc/semihosting_arm_emulation/armv8_aarch32/swisoft_armv8.cmm在这里插入图片描述

AArch32 DCC Communication Mode (DCC = Debug Communication Channel)

SVC异常将会触发一个semihosting异常处理器。它用于基于与主机通信的JTAG接口的DCC。目标程序将不会停止,但是semihosting异常处理器需要被加载或者连接到该程序。这个模式只当目标板提供DCC模式时被使用。
An example (swidcc_x.cmm) and the source of the Arm compatible semihosting handler (t32swi.c,
t32helper_x.c) can be found in ~~/demo/arm/etc/semihosting_arm_dcc
在这里插入图片描述

semihosting 性能描述

事实上,semihosting 机制并不能提供高性能的IO系统访问。每次进行semihosting操作,在进行数据传输时,处理器基本上都是处于停止状态的。这所需的时间在一定程度上取决于目标CPU、调试探针/链接(因此Red probe +在PC- link上提供了大大增强的半托管速度)、PC硬件和PC操作系统。所以semihosting 需要一定的时间,这可能会使用户的代码运行得更慢。所以在调试程序性能问题的时候,尽量不要使用printf()打印。

semihosting使用注意事项

当用户使用了semihosting库后,用户的应用程序将不再独立工作——它只会在连接到调试器时工作。
semihosting操作会导致CPU进入“调试状态”,这意味着在目标cpu和主机PC之间的数据传输期间,目标cpu上不会执行任何代码(包括中断)。
因此,如果用户的应用程序使用了中断,那么通常建议在中断活动中避免使用semihosting,对于一般程序来讲就是printf()了。如果仍然需要使用printf,那么建议使用可替代的通信接口,比如UART。

参考文档

https://www2.lauterbach.com/pdf/debugger_armv8v9.pdf
https://community.nxp.com/t5/LPCXpresso-IDE-FAQs/What-is-Semihosting/m-p/475390
https://github.com/ARM-software/abi-aa/blob/2982a9f3b512a5bfdc9e3fea5d3b298f9165c36b/semihosting/semihosting.rst

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SOC罗三炮

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值