[经验] 通过DAP下载运行程序

三亚东北人   2021-6-12 22:25 楼主

通过DAP下载运行程序

 

对于一般程序调试,获取通用寄存器的状态是比较重要的一种调试手段,读取这些通用寄存器的状态的前提是CORE必须处于HALT状态,否则这个寄存器的值是一直变化的,我们也就无法获取一个比较准确的值。另外对这些寄存器的值进行修改也需要将CORE HALT。

通过DAP HALT ARM CORE的方式也是访问一系列系统寄存器完成的,这些内核调试寄存器定义如下:

地址 类型 复位值 描述
0xE000EDF0 读写 0x00000000 调试停止控制和状态寄存器
0xE000EDF4 只写 - 调试内核寄存器的选择寄存器
0xE000EDF8 读写 - 调试内核寄存器数据寄存器
0xE000EDFC 读写 0x00000000 调试异常和监控控制寄存器

调试停止控制和状态寄存器

位范围 R/W 名称 功能
[31:16] W DEBGKEY 写操作必须是0xA05F,否则写操作被忽略,读操作返回状态位
[25] R S_RESET_ST 自上一次读该位时,系统已经复位或正在复位,读造作清零
[24] R S_RETIRE_ST 表示自上一次读该位时,已经执行一条指令
[19] R S_LOCKUP 系统处于lockup状态
[18] R S_SLEEP 系统处于睡眠状态,必须使用C_HALT来获得或者等待中断唤醒内核
[5] R/W C_SNAPSTALL 使能停止调试来获得对内核的控制,如果内核正在加载、存储操作,则操作无效,指令强制执行,如果C_DBUGEN=1, C_HALT=1,该位只能置1
[3] R/W C_MASKINS 处于调试状态的内核执行单布或运行时屏蔽中断,NMI依然有效
[2] R/W C_STEP 对内核进行单步操作,C_DEBUGEN=0时无效,S_HALT=1时仅修改
[1] R/W C_HALT 停止内核,内核停止时(比如断点)自动置位,C_DEBUGEN=1时只能写,该位置位时C_DEBUGEN也必须写1
[0] R/W C_DEBUGEN 使能调试,只能通过AHP-AP写入,内核不能写

调试内核选择寄存器

位范围 R/W 名称 功能
[16] W REGWnR 写操作为1,读操作为0
[4:0] W REGSEL 0000 - R0
...
1111 - R15
10000 - xPSR/Flags
10001 - MSP
10010 - PSP
10011 - RAZ/WI
10100 - CONTROL/FAULTMASK/BASEPRI/PRIMASK

写通用寄存器的流程

  1. 想挑事停止和状态寄存器中写入0xA05F0003,该操作会使能调试并停止内核
  2. 等待调试停止和状态寄存器的S_HALT置位,置位表示内核已经停止
  3. 向调试内核寄存器的数据寄存器中写入目标值
  4. 向调试内核寄存器选择寄存器写入要写入的寄存器编号和写操作标志

这个操作用Jlink Command的方式写下来就是下面这个样子:

connect
// select AP[1]
writedp 2 01000000
// halt core
writeap 1 E000EDF0
writeap 3 A05F0003
// set pc
writeap 1 E000EDF8
writeap 3 06000000
writeap 1 E000EDF4
writeap 3 0001000F
// release pc
writeap 1 E000EDF0
writeap 3 A05F0000

这个时候就可以直接写个生成JLink脚本的小脚本,用于直接下载程序了:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import sys
import binascii

bin_path = sys.argv[1]
start = """connect
writedp 2 01000000
// halt core
writeap 1 E000EDF0
writeap 3 A05F0003
// write code"""

start_address = 0x06000000
end = """ // set pc
writeap 1 E000EDF8
writeap 3 06000000
writeap 1 E000EDF4
writeap 3 0001000F
// set msp
writeap 1 E000EDF4
writeap 3 00010101
writeap 1 E000EDF8
writeap 3 0602807c
// release pc
writeap 1 E000EDF0
writeap 3 A05F0000"""

print(start)
with open(bin_path, 'rb') as src:
    word = src.read(4)
    while word != b'':
        print("writeap 1 %08x" % start_address)
        print("writeap 3 %08x" % int.from_bytes(word, byteorder='little'))
        start_address += 4
        word = src.read(4)
print(end)

回复评论 (1)

楼主的能生成JLink脚本的小脚本

很好,收藏了

点赞  2021-6-13 10:53
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复