zoukankan      html  css  js  c++  java
  • 痞子衡嵌入式:揭秘i.MXRT600的ISP模式下用J-Link连接后PC总是停在0x1c04a的原因(Debug Mailbox)


      大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家介绍的是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上也操作一次:

      我们发现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。

      我们知道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串行下载/启动流程。

      debug_mailbox_GetRequest()函数是Debug Mailbox机制的核心,它借助的是如下三个Mailbox寄存器来实现调试器与ROM的互动。

    • CSW:命令状态寄存器,调试器操作这个寄存器指示ROM进入mailbox命令解析状态
    • REQUEST:请求寄存器,调试器将mailbox命令写入这个寄存器指示ROM去执行
    • RETURN:结果寄存器,调试器通过读这个寄存器获取ROM执行mailbox命令结果

      对于使用者来说,一般借助调试器先向CSW寄存器写入0x21申请re-sync同时reset device ,然后再按需写入如下具体的命令进REQUEST寄存器,便可实现Debug Mailbox相应功能。

    #define ENTER_DEBUGGER_MAILBOX (0x0001)  // Start Mailbox debug
    #define GET_CRP_LEVEL          (0x0002)  // Deprecated and retuen 3
    #define DM_ERASE_FLASH         (0x0003)  // Mass erase flash
    #define EXIT_DEBUGGER_MAILBOX  (0x0004)  // Exit Mailbox debug
    #define ENTER_ISP_MODE         (0x0005)  // Enter specified ISP mode
    #define SET_FA_MODE            (0x0006)  // Set to "Fault Analysis" mode
    #define START_DEBUG_SESSION    (0x0007)  // Start Debug session
    #define DEBUG_AUTH_START       (0x0010)  // Start Debug Authentication Protocol
    #define DEBUG_AUTH_RESP        (0x0011)  // Debug Authentication response
    

      了解了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寄存器开启芯片调试模式。

    void InitTarget(void) {
      int v;
    
      JLINK_CORESIGHT_Configure("IRPre=0;DRPre=0;IRPost=0;DRPost=0;IRLenDevice=4");
      // Pre-select that we have a Cortex-M33 connected
      CPU = CORTEX_M33;
      // J-Link is allowed to use a TAP reset for JTAG-chain auto-detection
      JTAG_AllowTAPReset = 0;
    
      JTAG_SetDeviceId(0, 0x6BA02477);
    
      // Read AP ID register to identify DM AP at index 2
      JLINK_CORESIGHT_WriteDP(2, 0x020000f0);
      v = JLINK_CORESIGHT_ReadAP(3);
      JLINK_SYS_Report1("DAP-IDCODE:", v);
      // Select DM AP index 2
      JLINK_CORESIGHT_WriteDP(2, 0x02000000);
      JLINK_CORESIGHT_ReadDP(0);
    
      // Active DebugMailbox
      JLINK_CORESIGHT_WriteAP(0, 0x21);
      JLINK_CORESIGHT_ReadAP(0);
    
      // Enter Debug Session
      JLINK_CORESIGHT_WriteAP(1, 0x07);
      JLINK_CORESIGHT_ReadAP(0);
    }
    

    五、芯片调试模式(REQUEST = 0x07)下的状态

      前面讲了JLink Script会使芯片进入调试模式,那调试模式下芯片到底是什么状态?ROM其实是通过如下函数加载执行了0x1c040 - 0x1c04B处的一小段代码,并最终停在了0x1c04a处的while(1);,至此真相大白。

    void go_debug_mode(void)
    {
    #define VECTOR_DUMMY_ROUTINE 0x0001c000u
    #define APP_ENTRY (VECTOR_DUMMY_ROUTINE + 0x40 + 1)
        uint32_t dummy_loop_routines[] = {
            VECTOR_DUMMY_ROUTINE + 0x1000, // SP
            APP_ENTRY,                     // Reset Handler
            APP_ENTRY,                     // NMI Handler
            APP_ENTRY,                     // HardFault_Handler
            APP_ENTRY,                     // MemManage_Handler
            APP_ENTRY,                     // BusFault_Handler
            APP_ENTRY,                     // UsageFault_Handler
            APP_ENTRY,                     // SecureFault_Handler
            0,                             // Reserved
            0,                             // Reserved
            0,                             // Reserved
            APP_ENTRY,                     // SVC_Handler
            APP_ENTRY,                     // DebugMon_Handler
            0,                             // Reserved
            APP_ENTRY,                     // PendSV_Handler
            APP_ENTRY,                     // SysTick_Handler
            // Below are the binary codes for : 
            //   register uint32_t dummy = SCB->CPUID; 
            //   while(1);
            0x5000f64eu,
            0x0000f2ceu,
            0xe7fe6801u,
        };
    
        {
            uint32_t *dest = (uint32_t *)VECTOR_DUMMY_ROUTINE;
            uint32_t *src = (uint32_t *)&dummy_loop_routines[0];
            for (uint32_t i = 0u; i < ARRAY_SIZE(dummy_loop_routines); i++)
            {
                *dest++ = *src++;
            }
            jump_to_boot_image(VECTOR_DUMMY_ROUTINE);
        }
    }
    

    六、Debug Mailbox对JLink调试的影响

      基于上面分析,最后痞子衡再总结一下Debug Mailbox对JLink调试的影响:

    1. 当芯片在ROM中执行(比如ISP模式,比如Flash中没有应用程序)时,JLink要想正常连接,必须加载使能芯片调试模式的Script才行,否则会连不上芯片。
    2. 通过加载执行JLink Script成功连接上芯片后,PC总是停在0x1c04a,这是Debug Mailbox机制决定的。
    3. 只有当芯片正常启动Flash里的应用程序后(即离开了ROM),用JLink连接芯片(选择CM33,不加载Script),halt住内核,PC指向的才是真实的应用程序位置。

      至此,i.MXRT600中的Debug Mailbox实现对JLink调试的影响痞子衡便介绍完毕了,掌声在哪里~~~

    欢迎订阅

    文章会同时发布到我的 博客园主页CSDN主页知乎主页微信公众号 平台上。

    微信搜索"痞子衡嵌入式"或者扫描下面二维码,就可以在手机上第一时间看了哦。

  • 相关阅读:
    HDU3336 Count the string —— KMP next数组
    CodeForces
    51Nod 1627 瞬间移动 —— 组合数学
    51Nod 1158 全是1的最大子矩阵 —— 预处理 + 暴力枚举 or 单调栈
    51Nod 1225 余数之和 —— 分区枚举
    51Nod 1084 矩阵取数问题 V2 —— 最小费用最大流 or 多线程DP
    51Nod 机器人走方格 V3 —— 卡特兰数、Lucas定理
    51Nod XOR key —— 区间最大异或值 可持久化字典树
    HDU4825 Xor Sum —— Trie树
    51Nod 1515 明辨是非 —— 并查集 + 启发式合并
  • 原文地址:https://www.cnblogs.com/henjay724/p/14027404.html
Copyright © 2011-2022 走看看