目录
Mailbox是NXP LPC系列产品新推的一项功能。Debugger可以通过mailbox与ROM通信,实现Flash Erase、Enter ISP mode、debug authentication等功能。
Mailbox架构图
Mailbox 寄存器
Mailbox有三个寄存器
- CSW(Command status and Word register)
Debugger可以通过这个寄存器指示ROM进到mailbox handler,ROM、Debugger可以通过这个寄存器获知通信状况。 - Request register
Debugger向这个寄存器写入数据,ROM从该寄存器中获取数据执行相应的操作。 - Return register
ROM向此寄存器写入数据,debugger可以从该寄存器获取ROM的信息。
SWD访问mailbox示意图
SWD访问APB-AP,实现跟Mailbox的通信
- AP: Access Port。 绿色圈内所示连接到Mailbox
- DP: Debug Port。 就是我们的Jlink
ROM Mailbox Handler功能解析
Request/Response机制
Mailbox基于Request/Response机制,如下图:
- Debugger向CSW写入0x21,申请re-sync同时reset
- ROM检测CSW re-sync被置1,进入mailbox handler,向response寄存器写入0x0.等待debugger的请求。
- Debugger向request寄存器写入数据
- ROM获取reqeust寄存器中的数据,根据不同的指令进行相应的处理(比如擦除flash),向response寄存器中写入数据。
- Debugger可以根据response寄存器中的数据判断指令是否执行成功
ROM支持的Mailbox指令
- START_DBG_MB - 0x0001
- GET_CRP_LEVEL - 0x0002, Deprecated ans return 3
- ERASE_FLASH - 0x0003,
- EXIT_DBG_MB - 0x0004,
- ENTER_ISP_MODE - 0x0005,
- SET_FA_MODE - 0x0006,
- DBG_AUTH_START - 0x0010
- DBG_AUTH_RESP - 0x0011
ROM Error Defination
ERR_DM_BASE = 0x00100000, ERR_DM_NOT_ENTERED = ERR_DM_BASE + 1, /*0x00100001*/ ERR_DM_UNKNOWN_CMD = ERR_DM_BASE + 2, /*0x00100002*/ ERR_DM_COMM_FAIL = ERR_DM_BASE + 3, /*0x00100003*/
SWD访问Mailbox流程
以进入ISPmode为例
- Debugger选择APB-AP,访问mailbox
- Debugger向CSW写入0x21,申请re-sync同时reset
- ROM检测到re-sync信号,reset mailbox,进入mailbox handler,等待debugger的指令
- Debugger发送0x10005至request寄存器(如上如示ENTER_ISP_MODE = 0x5,高16bit为1表示通知ROM接下来还要发送一个参数,ROM根据这个参数使用相应的peripheral进入ISP)
- ROM读取request寄存器中数据,发现需要一个参数,向reponse寄存器中写入0x1A5A5。告知debugger其已经获知需要一个参数
- Debugger向request寄存器发送0x7(Use UART\SPI\I2C进入ISP mode)
- ROM检测SOCU是否使能了ISPCMDENROM,如果是则向response写入0x0然后根据参数0x7进入ISP mode。否则向response写入ERR_DM_UNKNOWN_CMD
发送Authen Start命令获取数据
- Debugger向ROM发送authen start命令后,接下来向ROM发送索取数据的长度+0xA5A5. authentication结构体的长度是0x1A,
- Debugger发送0x1AA5A5后,ROM会检测低16bits是否为0xA5A5并校验长度是否为0x1A,正确后发送一个word的数据给debugger
- Debuuger获取到数据后,长度减1未0x19A5A5,再次请求获取数据
- ROM检测低16bits是否为0xA5A5并且校验长度是否为0x19,通过后返回一个word的数据给Debugger
- 直到Debugger发送0xA5A5告知ROM数据已经全部获取后,ROM停止数据的发送
ROM发送的数据结构体如下:
typedef struct __attribute__ ((packed)) debug_auth_version {
uint16_t major;
uint16_t minor;
} debug_auth_version_t;
typedef struct __attribute__ ((packed)) debug_auth_challenge {
debug_auth_version_t version;
uint32_t socc;
uint32_t device_uuid[4];
debug_rotid_t rotid;
uint32_t cc_socu_pinned;
uint32_t cc_socu_default;
uint32_t cc_vu;
uint8_t challengeVector[32];
} debug_auth_challenge_t;
Debugger发送Authen response命令向ROM发送数据
以证书长度为2048bit长度的case为例:
- Debugger向ROM发送0x12C0011,请求向ROM发送认证数据。0x12C为证书长度为2048bit时,ROM需要的认证数据的长度
- ROM接到认证请求后,返回需要认证数据的长度0x12C+0xA5A5
- Debugger发送数据
- ROM接到数据后,长度减1,返回0x12BA5A5
- 所有数据传送完毕后,ROM返回0,然后进行认证
示例Code
使用Python撰写,调用pylink实现debugger跟mailbox的通信
import pylink
import pylink.protocols.swd as swd
from time import sleep
class jlink(object):
def __init__(self):
self.jlink = pylink.JLink()
self.jlink.target_connection_required = False
self.jlink.open()
self.jlink.set_tif(pylink.enums.JLinkInterfaces.SWD)#select APB-AP to communicate with mailbox
self.jlink.coresight_configure()
request = swd.WriteRequest(2, data=(0x000000F0 | (2 << 24)), ap=False)
response = request.send(self.jlink)
assert response.ack(), "No ack from JLink"
request = swd.WriteRequest(2, data=(0x00000000 | (2 << 24)), ap=False)
response = request.send(self.jlink)
assert response.ack(), "No ack from JLink"
def swd_write(self, addr, value):
request = swd.WriteRequest(addr/4, data = value, ap = True)
response = request.send(self.jlink)
assert response.ack(), "No ack from JLink"
print('send value to addr 0x%x'%addr)
print('value is 0x%x'%value)
def swd_read(self, addr):
request = swd.ReadRequest(addr/4, ap = True)
response = request.send(self.jlink)
assert response.ack(), "No ack from JLink"
sleep(0.1)
request2 = swd.ReadRequest(3, ap = False)
response2 = request2.send(self.jlink)#read data from DP register3, not got data correctly from response register
print ("read data: 0x%08x"%response2.data)
#start neter into mailbox
jlink = jlink()
jlink.swd_write(0, 0x21)
jlink.swd_read(0)
#enter isp mode
jlink.swd_write(4, 0x100005)
sleep(1)
jlink.swd_read(8)
jlink.swd_write(4, 0x7)
sleep(1)
jlink.swd_read(8)