赞
踩
ARM的外部调试模型并没有一个全局的使能控制bit,而是单独对每个外部调试事件,有对应的控制bit可以配置,从而控制该调试事件是否能将处理器停止。
比如 断点事件(Breakpoints event)和观察点事件(watchpoints)是self-host 调试模型和外部调试模型共享的资源,将 EDSCR(外部调试控制和状态寄存器)的HDE(Halting debug enable)字段设成1, 可以使能Breakpoint, Watchpoint 以及Halt Instruction 等debug events将处理器停止。
此外,外部调试器需要自我鉴权(authenticate itself),如果没有自我鉴权,让CPU停止运行的调试事件可能会被禁止。鉴权操作可能以多级鉴权的形式存在,比如当处理器处于Non-secure下时,需要一级鉴权来使能停止处理器的行为;当处理器处于secure下时,可能又需要另一级鉴权。
当处理器进入调试状态(debug state)后,外部调试器将接管并控制处理器。外部调试器也同样可以让处理器离开debug state,让其继续正常执行程序。
在处理器和外部调试器之间控制信息传送的机制称为握手,一个典型的握手操作有如下:
接下来,本文将介绍可以让处理器进入调试模式的各种外部调试事件(external debug events)。
对于处理器来讲,一个外部调试请求事件是一个输入的触发事件。当处理器收到该事件,将会进入debug state。外部调试器一般通过写 CTI 寄存器( Cross Trigger Interface Registers),来触发一个External debug request event,强制让处理器进入debug state,进而控制处理器。
如果处理器已经处于debug state,此时收到的External debug request将会被忽略。外部调试器如果想让处理器离开debug state继续执行程序,也可以通过写CTI寄存器触发一个restart request事件,当该事件被处理器收到,处理器将离开debug state。
当处理器主动执行 HLT 指令时, 处理器会进入debug state,并会触发一个 halt instruction debug event,该事件将允许外部调试器接管处理器。HLT指令同样也是用于停止处理器的软件断点指令。如果EDSCR的HDE为1,HLT指令将被允许执行,Halt instruction debug event也会被允许产生。一旦处理器执行HLT指令,处理器将进入debug state,并将控制器交给外部调试器。此外,AArch64状态下的semihosting的实现,也是通过HLT指令来实现,详情介绍参考博客:什么是Semihosting(半主机)- ARM处理器与主机之间IO通信机制
HLT指令的一大用途就是用来打断点。外部调试器比如要在程序中的某个位置A处打断点,调试器可以将地址A处的指令替换成HLT指令,一旦程序执行到了地址A,HLT指令将会触发一个Halt instruction debug event,之后外部调试器便可以控制处理器了。
如果想要离开debug state,外部调试器也可以触发一个restart 事件让处理器继续运行。
Halting step debug event可以让外部调试器对程序进行单步调试:让处理器在不处于debug state状态下单步执行指令或者异常。换句话说,就是执行指令的时候处理器不处于debug state,当该指令执行完成又进入debug state,从而达到单步调试的目的。具体实现有如下步骤:
当处理器处于debug 状态下时,外部调试器可以通过将EDECR寄存器的SS字段写1, 将单步调试功能enable。需要注意的是,当处理器不处于debug state时,改变EDECR.SS的值,其行为是CONSTRAINED UNPREDICTABLE,可能会有如下行为发生:
外部调试器会发出信号让处理器离开debug state。
在离开debug state之后,处理器将执行PC寄存器中地址上指向的指令,并且处理器将会在执行下一条指令之前再次进入debug state,随即又把控制权交给外部调试器。
单步调试的流程可以总结为如上三个步骤,处理器在单步调试过程中,不断地在debug state和正常状态中切换,其中是有一个状态机:the Halting Step state machine来维护该操作的。
当处理器进入异常或者从异常退出时,异常捕获调试事件可以让外部调试器接管处理器。
对于每个异常等级,在ED Exception Catch Control Register (EDECCR)中都有对应的控制bit,通过配置这些控制位(每个目标异常等级和Secure状态都有不同的控制位),当处理器在对应异常等级和安全状态下,进入异常或者异常返回时,处理器会进入debug state:
下图为EDECCR, External Debug Exception Catch Control Register寄存器的控制位示意图,其中NS表示Non-secure,S表示Secure;E表示进入异常,R表示异常返回。最后的数字0 1 2 3表示异常等级。所以该寄存器可以控制所有状态下的异常捕获。
当发生reset时,异常捕获事件可以允许外部异常调试器立刻接管处理器。
如果想要使能Reset catch debug event,可以配置以下两个寄存器的Reset Catch debug Event (RCE) 控制位:
对处理器来讲,无论是Warm reset 还是 Cold reset,只要当RCE控制位被置上,当reset发生后,处理器就会在执行第一条指令之前,进入debug state,并将控制权交给外部调试器。
A software access debug event allows the external debugger to take control of the PE when the PE
software tries to access the following registers:
当External Debug Status and Control Register (EDSCR)寄存器的TDA控制位被设为1,处理器执行的软件试图访问以下寄存器时:
将会触发software access debug event,进而处理器会进入debug state。
关于TDA控制位,参考如下:
当TDA为1时,software access debug event可以软件通过访问以下debug寄存器的方式触发,进而进入debug state:
在处理器电源断电时,一些调试寄存器内容将会丢失。为了在reset后恢复处理器的调试能力,必须将调试寄存器内容保存到非易失性内存中,并在系统复位后restore。Armv8-A体系结构支持使用操作系统保存机制(OS save mechanism)保存调试寄存器内容,并使用操作系统恢复机制(OS restore mechanism)恢复调试寄存器内容。
处理器软件负责执行保存和恢复。在保存调试寄存器内容时,软件会给 OS lock上锁,以便禁止外部调试访问调试寄存器。恢复调试寄存器内容后,PE软件会解锁 OS lock。
OS unlock catch debug event允许外部调试器在OS restore sequence后立即控制处理器。此事件强制处理器在reset后恢复调试寄存器器的内容后,并立即进入调试状态。
EDECR寄存器的OSUCE控制位可以控制 OS unlock catch debug event是否能被触发。
外部调试器可以先在硬件断点(Hardware breakpoint)寄存器里写入断点的地址。当处理器执行到该地址的指令时,如果满足以下条件,将生成一个断点事件(Breakpoint event):
EDSCR.HDE ==1, 表示 Halting debug is enabled 。
鉴权信号表明当前的调试器已经为当前安全状态下的处理器完成了自我鉴权。
上文提到过可以通过HLT指令设置software Breakpoint,而这种通过配置硬件寄存器的方式实现的Breakpoint,则称为硬件断点(hardware breakpoint)。
参考下图的示例,以下是设置硬件断点的流程:
首先外部调试器需要将需要打断点的指令所在的地址写入DBGBVR(Breakpoint Value Register) 寄存器。比如想在0x9014地址上设置一个断点,则将该地址写入DBGBVR1_EL1中。
然后外部调试器将对应的断点控制寄存器DBGBCR1_EL1的E控制位写1,表示使能了断点事件。
如果处理器执行到了0x9014上的指令,则会触发Breakpoint event。
断点控制寄存器(Debug Breakpoint Control Registers)DBGBCR_EL1包含针对断点的控制位,主要是 E 位:
如果E控制位为0,那么将不能产生Breakpoint 事件。此外,在reset后,DBGBCRn.E的值是未知的,所以外部调试器在进行调试之前,必须确保它有个确定的值。
断点值寄存器DBGBVR_EL1保存用于对应断点匹配的值。该值可以是:
The range of n for DBGBCRn is 0 to 5.
Armv8-A架构提供了2-16个可实现的硬件断点,可以通过寄存器ID_AA64DFR0_EL1的BRPs字段来知道具体实现了多少个断点单元。比如在Cortex-A55架构下,最多支持6个硬件断点。
可以通过配置单个调试断点控制寄存器DBGBCR_El1.E的E位来启用或禁用单个断点单元。每个断点单元都有一个相应的控制寄存器。根据实现的断点数量,寄存器的编号将按照如下方法进行:
A watchpoint event is generated when a PE accesses data memory from a particular address
or address range. Hardware watchpoint registers can be programmed with the address of a
data memory location. When the PE attempts to access data from the programmed address, a
watchpoint event is generated.
通过配置硬件监视点(Hardware watchpoint)寄存器,写入需要被监控的数据所在的内存地址,当处理器从该特定地址或地址范围访问数据内存时,就会生成监视点事件。当生成监视点事件(Watchpoint event)时,PE将进入调试状态。同Breakpoint event一样,也需要满足一下两个条件:
Watchpoint 永远不会在指令获取(instruction fetch)时生成监视点调试事件。使能Hardware watchpoint的流程:
观察点可以是:
Armv8架构提供了2-16硬件监视点实现。可以通过查看ID_AA64DFR0_EL1的WRPs字段,看具体实现了多少个监视点单元。比如在Cortex-A55架构下,最多支持4个硬件断点。
可以通过编程单个调试监视点控制寄存器DBGWCR_EL1.E的E位来启用或禁用单个监视点单元。每个监视点单元都有一个相应的控制寄存器。根据实现的观察点寄存器编号可以找到对应关系:
嵌入式交叉触发器(Embedded Cross Trigger,ECT)是Armv8- A系统中的外部调试器用于生成调试事件的一种机制。ECT还支持将调试事件从一个代理路由到系统中的另一个代理。外部调试器可以使用ECT来生成debug request或restart request。这些事件会触发处理器之间的路由事件。例如,这些事件可以将一个debug request 事件从一个处理器路由到其他处理器。这样的话,当系统中的一个处理器停止时,系统中的其他所有处理器都可以停止。
Armv8-A 架构下的ECT包括如下三部分:
CTI提供了跨Armv8-A系统的各个组件路由触发事件的能力。例如,将触发事件路由到系统中的中断控制器(GIC),trace units或者其他处理器。如果系统中存在多个CTI模块,则可以使用ETM在CTI模块之间传递事件。CTM使用如下的IO 通道在CTM模块之间传递事件:
在Armv8-A架构中,有一些CTI的output 触发事件已经被固定用途,比如:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。