请选择 进入手机版 | 继续访问电脑版
查看: 143|回复: 0

[分享] 为何用JLink连接上这款MCU后PC指向0x1c04a?

[复制链接]
  • TA的每日心情
    开心
    6 天前
  • 签到天数: 87 天

    [LV.6]常住居民II

    1608

    主题

    3010

    帖子

    0

    金豆

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    15162
    最后登录
    2021-1-26
    发表于 2020-11-25 13:27:29 | 显示全部楼层 |阅读模式
    为何用JLink连接上这款MCU后PC指向0x1c04a?


    大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家介绍的是i.MXRT600中的Debug Mailbox实现对JLink调试的影响。


    事情缘起痞子衡的同事 - 喜欢打破砂锅问到底的Kerry小姐姐,她最近在研究i.MXRT600这款芯片,她发现在芯片ROM串行下载(ISP)模式下,连上芯片USB端口可以在设备管理器中正常看到枚举的HID设备(0x1fc9,0x0020),这个HID设备可配合上位机工具blhost.exe进行应用程序下载。但是当使用JLink正常连上芯片(选择的是MIMXRT685,不是CM33)后,之前的那个HID设备不见了,看起来芯片像是退出了ROM正常运行,这个体验跟i.MXRT1050上不太一样,这是为什么?这其实是Debug Mailbox在捣鬼,且听痞子衡细聊:

    一、引出调试问题
    按照我们之前在i.MXRT1050上的调试经验,将芯片设为串行下载模式后,使用JLink连接上芯片,并halt住内核,此时芯片PC是正常停在ROM区域的(0x200000之后),让我们同样的过程在i.MXRT600上也操作一次:
    1.png
    我们发现PC指向了0x1c04a,并且不管你如何reset再重新halt,它一直停在这个地方,更奇怪的是这个地方不在ROM区域(0x03000000或0x13000000之后)里,这是怎么回事?


    二、什么是Debug Mailbox?
    与i.MXRT1050不同的是,i.MXRT600中引入了Debug Mailbox机制,这个机制由ROM负责实现,因此连接上JLink后的行为是由Debug Mailbox机制决定的。


    翻开i.MXRT600的User Manual,在Debug subsystem这一章节可以找到Debug Mailbox相关信息,Debug Mailbox其实最早是NXP LPC系列新推的一项功能,后来也用在了i.MXRT600上面。


    下图是i.MXRT600的SWD调试系统内部连接图,其中蓝框标出的DM AP便是Debug Mailbox。
    2.png
    我们知道i.MXRT600是基于Cortex-M33内核的MCU,这款ARM内核主打特点是安全,因此NXP在设计芯片时也加入了很多安全方面的特性,Debug Mailbox便是其一,Debug Mailbox基于NXP debug authentication protocol version 1.0,主要作用是实现外部调试器与芯片内ROM的通信,从而赋予调试器擦写Flash、进入ROM ISP、调试认证等功能。


    三、ROM中Debug Mailbox实现
    那么ROM中的Debug Mailbox机制到底是什么?简单理解就是如下一段代码插入了ROM的初始化流程。这个机制其实很简单,就是确保debug特性是正常开启的,然后根据芯片复位类型来初始化debug port并决定要不要进入Mailbox命令处理。


    // 确认IFR里debug特性正常开启
    if (kStatus_DBG_Success != debug_auth_evaluate_dcfg_socu())
    {
        __set_FAULTMASK(1);
        __WFI();
    }
    volatile uint32_t reset_status = RSTCTRL0->SYSRSTSTAT;
    // 根据复位类型设置初始debug port状态
    if (kStatus_DBG_Success != debug_auth_hal_set_initial_debug_port_state(reset_status))
    {
        __set_FAULTMASK(1);
        __WFI();
    }
    if (reset_status & 0x20)
    {
        // 处理mailbox收到的来自debugger的命令
        debug_mailbox_GetRequest();
    }
    RSTCTRL0->SYSRSTSTAT[5]位即ARM_APD_RESET,表明ARM内核是否发生了软复位(warm reset),正常芯片上电,这个位不会被置1,但是如果有调试器接入给内核发软复位,这个位就会被置位。一旦这个位被置起来,ROM初始化过程中便会进入Mailbox命令处理函数debug_mailbox_GetRequest(),不再往后执行正常的ROM串行下载/启动流程。
    3.png
    debug_mailbox_GetRequest()函数是Debug Mailbox机制的核心,它借助的是如下三个Mailbox寄存器来实现调试器与ROM的互动。


    CSW:命令状态寄存器,调试器操作这个寄存器指示ROM进入mailbox命令解析状态
    REQUEST:请求寄存器,调试器将mailbox命令写入这个寄存器指示ROM去执行
    RETURN:结果寄存器,调试器通过读这个寄存器获取ROM执行mailbox命令结果
    4.png
    对于使用者来说,一般借助调试器先向CSW寄存器写入0x21申请re-sync同时reset device ,然后再按需写入如下具体的命令进REQUEST寄存器,便可实现Debug Mailbox相应功能。
    1. #define ENTER_DEBUGGER_MAILBOX (0x0001)  // Start Mailbox debug
    2. #define GET_CRP_LEVEL          (0x0002)  // Deprecated and retuen 3
    3. #define DM_ERASE_FLASH         (0x0003)  // Mass erase flash
    4. #define EXIT_DEBUGGER_MAILBOX  (0x0004)  // Exit Mailbox debug
    5. #define ENTER_ISP_MODE         (0x0005)  // Enter specified ISP mode
    6. #define SET_FA_MODE            (0x0006)  // Set to "Fault Analysis" mode
    7. #define START_DEBUG_SESSION    (0x0007)  // Start Debug session
    8. #define DEBUG_AUTH_START       (0x0010)  // Start Debug Authentication Protocol
    9. #define DEBUG_AUTH_RESP        (0x0011)  // Debug Authentication response
    复制代码
    四、激活Debug Mailbox的JLink Script
    了解了Debug Mailbox机制原理,我们再来看JLink连接i.MXRT600时必须要加载执行的如下Script内容(开头痞子衡说了必须选择MIMXRT685,而不是CM33,因为在JLink DLL / JLinkDevices.xml里MIMXRT685才默认指定了配套Script脚本)。关于JLink Script知识,可以先看痞子衡之前文章 《JLink Script文件基础及其在IAR下调用方法》。

    这个脚本内容其实在i.MXRT600的User Manual中已经给出了相应伪代码,通过调用JLINK_CORESIGHT_WriteAP()来写Mailbox寄存器(index 0对应CSW,index 1对应REQUEST),基本是按照前面介绍的Debug Mailbox使用流程来的,最后通过写入START_DEBUG_SESSION命令进REQUEST寄存器开启芯片调试模式。
    1. void InitTarget(void) {
    2.   int v;

    3.   JLINK_CORESIGHT_Configure("IRPre=0;DRPre=0;IRPost=0;DRPost=0;IRLenDevice=4");
    4.   // Pre-select that we have a Cortex-M33 connected
    5.   CPU = CORTEX_M33;
    6.   // J-Link is allowed to use a TAP reset for JTAG-chain auto-detection
    7.   JTAG_AllowTAPReset = 0;

    8.   JTAG_SetDeviceId(0, 0x6BA02477);

    9.   // Read AP ID register to identify DM AP at index 2
    10.   JLINK_CORESIGHT_WriteDP(2, 0x020000f0);
    11.   v = JLINK_CORESIGHT_ReadAP(3);
    12.   JLINK_SYS_Report1("DAP-IDCODE:", v);
    13.   // Select DM AP index 2
    14.   JLINK_CORESIGHT_WriteDP(2, 0x02000000);
    15.   JLINK_CORESIGHT_ReadDP(0);

    16.   // Active DebugMailbox
    17.   JLINK_CORESIGHT_WriteAP(0, 0x21);
    18.   JLINK_CORESIGHT_ReadAP(0);

    19.   // Enter Debug Session
    20.   JLINK_CORESIGHT_WriteAP(1, 0x07);
    21.   JLINK_CORESIGHT_ReadAP(0);
    22. }
    复制代码
    五、芯片调试模式(REQUEST = 0x07)下的状态
    前面讲了JLink Script会使芯片进入调试模式,那调试模式下芯片到底是什么状态?ROM其实是通过如下函数加载执行了0x1c040 - 0x1c04B处的一小段代码,并最终停在了0x1c04a处的while(1);,至此真相大白。
    1. void go_debug_mode(void)
    2. {
    3. #define VECTOR_DUMMY_ROUTINE 0x0001c000u
    4. #define APP_ENTRY (VECTOR_DUMMY_ROUTINE + 0x40 + 1)
    5.     uint32_t dummy_loop_routines[] = {
    6.         VECTOR_DUMMY_ROUTINE + 0x1000, // SP
    7.         APP_ENTRY,                     // Reset Handler
    8.         APP_ENTRY,                     // NMI Handler
    9.         APP_ENTRY,                     // HardFault_Handler
    10.         APP_ENTRY,                     // MemManage_Handler
    11.         APP_ENTRY,                     // BusFault_Handler
    12.         APP_ENTRY,                     // UsageFault_Handler
    13.         APP_ENTRY,                     // SecureFault_Handler
    14.         0,                             // Reserved
    15.         0,                             // Reserved
    16.         0,                             // Reserved
    17.         APP_ENTRY,                     // SVC_Handler
    18.         APP_ENTRY,                     // DebugMon_Handler
    19.         0,                             // Reserved
    20.         APP_ENTRY,                     // PendSV_Handler
    21.         APP_ENTRY,                     // SysTick_Handler
    22.         // Below are the binary codes for :
    23.         //   register uint32_t dummy = SCB->CPUID;
    24.         //   while(1);
    25.         0x5000f64eu,
    26.         0x0000f2ceu,
    27.         0xe7fe6801u,
    28.     };

    29.     {
    30.         uint32_t *dest = (uint32_t *)VECTOR_DUMMY_ROUTINE;
    31.         uint32_t *src = (uint32_t *)&dummy_loop_routines[0];
    32.         for (uint32_t i = 0u; i < ARRAY_SIZE(dummy_loop_routines); i++)
    33.         {
    34.             *dest++ = *src++;
    35.         }
    36.         jump_to_boot_image(VECTOR_DUMMY_ROUTINE);
    37.     }
    38. }
    复制代码
    六、Debug Mailbox对JLink调试的影响
    基于上面分析,最后痞子衡再总结一下Debug Mailbox对JLink调试的影响:


    当芯片在ROM中执行(比如ISP模式,比如Flash中没有应用程序)时,JLink要想正常连接,必须加载使能芯片调试模式的Script才行,否则会连不上芯片。
    通过加载执行JLink Script成功连接上芯片后,PC总是停在0x1c04a,这是Debug Mailbox机制决定的。
    只有当芯片正常启动Flash里的应用程序后(即离开了ROM),用JLink连接芯片(选择CM33,不加载Script),halt住内核,PC指向的才是真实的应用程序位置。
    至此,i.MXRT600中的Debug Mailbox实现对JLink调试的影响痞子衡便介绍完毕了,掌声在哪里~~~



    文章出处:痞子衡嵌入式

    签到
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    关闭

    站长推荐上一条 /2 下一条

    Archiver|手机版|小黑屋|恩智浦技术社区

    GMT+8, 2021-1-26 20:32 , Processed in 0.070533 second(s), 14 queries , MemCache On.

    Powered by Discuz! X3.4

    Copyright © 2001-2020, Tencent Cloud.

    快速回复 返回顶部 返回列表