1. 程式人生 > >痞子衡嵌入式:系統時鐘配置不當會導致i.MXRT1xxx系列下OTFAD加密啟動失敗

痞子衡嵌入式:系統時鐘配置不當會導致i.MXRT1xxx系列下OTFAD加密啟動失敗

----   大家好,我是痞子衡,是正經搞技術的痞子。今天痞子衡給大家分享的是**系統時鐘配置不當會導致i.MXRT1xxx系列下OTFAD加密啟動失敗問題**。   我們知道,i.MXRT1xxx家族早期型號(RT1050/RT0160/RT1020)的硬體解密外設名字叫BEE,這個外設主要是配合FlexSPI外設去實現外接序列NOR Flash線上解密XIP執行用的。而到了最近的i.MXRT1xxx新型號(RT1010/RT1170)上,BEE外設被替換成了OTFAD外設,功能不變,解密效率得到了很大提升,但客戶在使能OTFAD加密啟動時常常遇到App無法正常執行問題,這其實跟OTFAD自身的一個時鐘小限制有關(這個限制在BEE上不存在),今天痞子衡就來好好聊一聊OTFAD的這個小限制: ### 一、問題描述   我們以i.MXRT1010為例,從恩智浦官網下載一個SDK包(痞子衡下的是v2.9.1),隨便選擇其中一個例程,就以最簡單的 \SDK\boards\evkmimxrt1010\demo_apps\led_blinky 為例吧。編譯這個 led_blinky 工程(選擇 flexspi_nor_debug build,即XIP工程),得到可執行檔案(實際bin檔案大小為10KB左右),使用 [NXP-MCUBootUtility](https://github.com/JayHeng/NXP-MCUBootUtility) 工具將可執行檔案(led_blinky.out)下載進MIMXRT1010-EVK開發板中(下載時啟動模式為2'b01,啟動時切換到2'b10),可以看到板載綠色LED小燈(D25)會閃,例程是可以正常工作的。   現在讓我們嘗試使能OTFAD加密,回到晶片下載模式依然藉助 NXP-MCUBootUtility 工具,將工具 Secure boot type 選項切換為 OTFAD Encrypted Image Boot,其他設定均預設(此時加密範圍是 0x60001000 - 0x60001fff,僅加密IVT等啟動頭,不含app),再次下載可執行檔案(led_blinky.out),換到晶片啟動模式復位板子,例程依舊是正常工作的,看起來OTFAD加密啟動似乎沒有問題。 ![](http://henjay724.com/image/cnblogs/iMXRT1010_OTFAD_Boot_Limit_default_protect_region.PNG)   讓我們再進一步,將加密範圍設定為0x60002000 - 0x60004fff,這時加密區域覆蓋到了整個app,重新按上述流程操作一遍,發現例程沒能正常工作,這時候OTFAD加密啟動出了問題,難道app區域不能被加密?那OTFAD加密還有啥意義? ![](http://henjay724.com/image/cnblogs/iMXRT1010_OTFAD_Boot_Limit_actul_protect_region.PNG)   app區域當然可以被加密,跟著痞子衡再做一次實驗,在 led_blinky.c 檔案的 main() 函式中,我們將時鐘配置函式 BOARD_BootClockRUN() 直接註釋掉或者在連結檔案裡將其全部搞成 __ramfunc(即在晶片內部RAM裡執行這部分時鐘配置程式碼),這個例程僅是利用SysTick定時翻轉GPIO,因此時鐘配置程式碼去掉不影響正常執行,重新編譯工程再按上面流程操作一遍,這時候例程又能正常工作了,說明加密後的app是能被OTFAD正常解密執行的。 ![](http://henjay724.com/image/cnblogs/iMXRT1010_OTFAD_Boot_Limit_comment_out_clk_cfg.PNG) - ![](http://henjay724.com/image/cnblogs/iMXRT1010_OTFAD_Boot_Limit_ramfunc_in_linker2.PNG)   現在的問題變成了為何OTFAD加密啟動時,BOARD_BootClockRUN() 函式不能在Flash裡執行,這就是問題所在。 ### 二、原因分析   關於上述問題的原因,痞子衡先直接給答案,這是OTFAD外設本身的時鐘小限制,當OTFAD被使能時,如果被加密的app程式碼是XIP執行,app裡做系統時鐘配置時要始終保證Core時鐘高於FlexSPI外設時鐘。如果Core時鐘低於FlexSPI時鐘,此時Core去訪問加密Flash區域,OTFAD無法正常解密,會導致指令錯亂,發生系統故障。 ![](http://henjay724.com/image/cnblogs/iMXRT1010_OTFAD_Boot_Limit_ccm_clk_tree.PNG)   我們配合上面的i.MXRT1010系統時鐘樹來認真分析下OTFAD這個時鐘限制問題。晶片上電總是從BootROM執行,BootROM會先將Core配置到396MHz,將FlexSPI時鐘根據使用者放置在Flash偏移0x400處的FDCB裡的設定配到30MHz - 200MHz不等,再讀取Flash偏移0地址處OTFAD DEK KeyBlob資料使能OTFAD,然後讀取IVT等頭資訊去跳轉到App。很顯然只加密IVT部分根本不受OTFAD限制的影響,這部分解析是在BootROM裡完成的,BootROM裡時鐘配置符合OTFAD時鐘限制要求。 ```text // BootROM裡對Core時鐘配置 CCM_ANALOG->PFD_528[PFD3_FRAC] = 24, PLL2 PFD3輸出 (528MHz * 18) / 24 = 396MHz CCM->CBCMR[PRE_PERIPH_CLK_SEL] = 2, 時鐘來自PLL2 PFD3 CCM->CBCDR[PERIPH_CLK_SEL] = 0, 核心時鐘來自CCM->CBCMR[PRE_PERIPH_CLK_SEL] CCM->CBCDR[AHB_PODF] = 0, 核心時鐘不分頻 // BootROM裡對FlexSPI時鐘配置 CCM_ANALOG->PFD_480[PFD0_FRAC] = x, PLL3 PFD0輸出 (480MHz * 18) / x CCM->CSCMR1[FLEXSPI_CLK_SEL] = 3, 時鐘來自PLL3 PFD0 CCM->CSCMR1[FLEXSPI_CLK_SRC] = 0, FlexSPI時鐘來自CCM->CSCMR1[FLEXSPI_CLK_SEL] CCM->CSCMR1[FLEXSPI_PODF] = y, FlexSPI時鐘做(y+1)分頻 ```   當BootROM跳轉到了App之後,我們再來看看App裡對時鐘是怎麼配置的,就是BOARD_BootClockRUN()函式,可以看到這個函式裡將核心頻率從BootROM設定的396MHz切換到外部OSC 24MHz。無論此時使用者FDCB裡對FlexSPI時鐘是多少配置,至少也會大於30MHz,那麼此時24MHz核心頻率一定會低於FlexSPI時鐘頻率,此時只要發生核心對Flash加密區域的訪問(時鐘配置程式碼就在Flash裡執行),就觸發了OTFAD時鐘限制問題,App就會跑飛。 ![](http://henjay724.com/image/cnblogs/iMXRT1010_OTFAD_Boot_Limit_sdk_clk_cfg.PNG) ### 三、解決方案   知道了原因,解決方案就簡單了,在App時鐘配置裡,不要按照尋常套路去先將核心時鐘源切換到外部OSC再切到PLL,而是直接切到PLL上。比如i.MXRT1010內部有個PLL6(也叫Audio PLL),固定500MHz,正好是App要的最終核心頻率,我們在BOARD_BootClockRUN()裡將Audio(Enet) PLL初始化設定程式碼提到前面,刪掉原來的切換OSC設定程式碼即可。 ```C void BOARD_BootClockRUN(void) { // 此處略去... /* Set Oscillator ready counter value. */ CCM->CCR = (CCM->CCR & (~CCM_CCR_OSCNT_MASK)) | CCM_CCR_OSCNT(127); - /* Setting PeriphClk2Mux and PeriphMux to provide stable clock before PLLs are initialed */ - CLOCK_SetMux(kCLOCK_PeriphClk2Mux, 1); /* Set PERIPH_CLK2 MUX to OSC */ - CLOCK_SetMux(kCLOCK_PeriphMux, 1); /* Set PERIPH_CLK MUX to PERIPH_CLK2 */ // 此處略去... /* Set IPG_PODF. */ CLOCK_SetDiv(kCLOCK_IpgDiv, 3); + /* Init Enet PLL. */ + CLOCK_InitEnetPll(&enetPllConfig_BOARD_BootClockRUN); + /* Set preperiph clock source. */ + CLOCK_SetMux(kCLOCK_PrePeriphMux, 3); // 此處略去... /* Enable Audio PLL output. */ CCM_ANALOG->PLL_AUDIO |= CCM_ANALOG_PLL_AUDIO_ENABLE_MASK; - /* Init Enet PLL. */ - CLOCK_InitEnetPll(&enetPllConfig_BOARD_BootClockRUN); - /* Set preperiph clock source. */ - CLOCK_SetMux(kCLOCK_PrePeriphMux, 3); // 此處略去... /* Set SystemCoreClock variable. */ SystemCoreClock = BOARD_BOOTCLOCKRUN_CORE_CLOCK; } ```   最後再提一下,這個OTFAD時鐘限制問題在i.MXRT1170上同樣存在,解決思路與上面類似,痞子衡就不再贅述了。   至此,系統時鐘配置不當會導致i.MXRT1xxx系列下OTFAD加密啟動失敗問題痞子衡便介紹完畢了,掌聲在哪裡~~~ ### 歡迎訂閱 文章會同時釋出到我的 [部落格園主頁](https://www.cnblogs.com/henjay724/)、[CSDN主頁](https://blog.csdn.net/henjay724)、[知乎主頁](https://www.zhihu.com/people/henjay724)、[微信公眾號](http://weixin.sogou.com/weixin?type=1&query=痞子衡嵌入式) 平臺上。 微信搜尋"__痞子衡嵌入式__"或者掃描下面二維碼,就可以在手機上第一時間看了哦。 ![](http://henjay724.com/image/github/pzhMcu_qrcode_258x258.jpg)