LPC之Mailbox

目录

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为例

  1. Debugger选择APB-AP,访问mailbox
  2. Debugger向CSW写入0x21,申请re-sync同时reset
  3. ROM检测到re-sync信号,reset mailbox,进入mailbox handler,等待debugger的指令
  4. Debugger发送0x10005至request寄存器(如上如示ENTER_ISP_MODE = 0x5,高16bit为1表示通知ROM接下来还要发送一个参数,ROM根据这个参数使用相应的peripheral进入ISP)
  5. ROM读取request寄存器中数据,发现需要一个参数,向reponse寄存器中写入0x1A5A5。告知debugger其已经获知需要一个参数
  6. Debugger向request寄存器发送0x7(Use UART\SPI\I2C进入ISP mode)
  7. 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)

猜你喜欢

转载自www.cnblogs.com/richard-xiong/p/10041482.html