Introduction
Pricinple & Machenism
HA01的內存地址空間
BOOT ROM簡介
BOOT ROM中的Bootloader執行過程
BVT的數據結構
Practice
源碼中關于BVT的設計
在集成開發環境中調試
Conclusion
Reference
Introduction
HA系列微控制器基于Arm Cortex-M7處理器內核,集成了Security Boot的功能。Security Boot的關鍵代碼集成在BOOT ROM中的bootloader程序中,用戶不可見,以確保信息安全的需要。然而,開發者在自行編譯固件時,需要配合BOOT ROM中的bootloader,才能正常地引導到用戶應用程序,完成啟動過程。
本文以HA系列的YTM32B1HA01微控制器(下文簡稱HA01)為例,將詳細介紹BOOT ROM中bootloader的運行機制,以及用戶程序與之對接的設計要點。
Pricinple & Machenism
HA01的內存地址空間
從RM手冊中可以找到HA01的內存地址空間映射表,如圖x所示。從表中可以看到,0x0000_0000開始的地址區是一塊ITCM存儲器(RAM),而存放用戶程序的pflash則被安排在0x0200_0000開始的地址區間。在0x0100_0000地址開始的內存空間中,安排了一塊ROM。按照芯片內部的硬件設計,芯片上電復位對硬件電路做好初始化后,先進入ROM執行預燒錄的bootloader程序,進一步引導至用戶應用程序。
圖x HA01的內存地址空間
在Arm Cortex-M7架構中,ITCM是專門用來存放程序指令(Instruction),DTCM是專門用來存放數據(Data),至于OCRAM,就對應于普通的SRAM。如果按照以往Arm Cortex-M架構中只區分flash和SRAM的用法,DTCM和OCRAM都可以當做是SRAM使用,所以用戶在常規用例的linker文件中,也可以把DTCM和OCRAM連續的地址空間都當做SRAM使用。但實際上,ITCM和DTCM都是TCM(Tightly Coupled Memories)存儲器,分別通過I-TCM和D-TCM總線訪問,是等同于Cache存儲器的角色,直接同Arm Cortex-M7內核相連,而不同于OCRAM(或者早先Arm Cortex-M架構中的RAM)是通過總線(AXI總線)間接同Arm Cortex-M7內核連通。如此,一般情況下,若沒有Cache加持,Cortex-M7內核訪問TCM的效率要高于訪問OCRAM。
對這些不同同種類的內存,可以根據需要靈活配置,以獲得最優的訪問效率。一種典型的用法:
在ITCM中存放中斷向量表。這也是為什么把ITCM安排到0x0000_0000地址的原因。但需要在執行到pflash中的用戶程序之后,由用戶程序將存放在pflash中的中斷向量表自行搬運到ITCM,然后修改Arm核心的VTOR寄存器重映射到0x0000_0000作為中斷向量表的基地址。如果ITCM的空間大于預留的中斷向量表占用的空間,剩下的空間用來存放ram code也是不錯的。
在DTCM中存放棧。方便處理器快速地申請和釋放。
在OCRAM中存放堆,以及用戶程序中定義的全局變量、緩沖區等。
OCRAM可能跟Cache搭配使用,以提高訪問效率,但如果處理器內核和DMA進行數據同步,Cache機制可能會引入一些麻煩,此時如果不想繁瑣地調整Cache的配置,也可以將需要同步的緩沖區安排到DTCM中。
BOOT ROM簡介
HA01上集成的BOOT ROM使用了64KB的存儲器。芯片復位后,Cortex-M7內核從ROM里的bootloader開始執行引導程序。其中,將解析存放在pflash開始位置的BVT(Boot Vector Table)。這里的bootloader主要用于實現四個功能:
安全啟動Security Boot
在信息安全的體系中,Security Boot作為整個安全系統的置信根(Root of Trust),可以使用CMAC授權算法,對用戶指定的程序(例如2nd bootloader或OTA)進行認證,這個過程中,利用硬件的HCU外設模塊進行計算,其配置信息存放在BVT中。進一步,HCU外設模塊使用的密鑰,存放在HCU_NVR中,由OEM主機廠或Tier-1預先燒錄,用戶全程不可見。
如果CMAC驗簽失敗,處理器內核可以繼續運行bootloader并引導至用戶程序,但HCU將不會導入存放與HCU_NVR中的密鑰,一切加密相關的操作將得不到芯片硬件的支持。
快速從Powerdown模式下喚醒
當檢測到從Powerdown模式下喚醒而產生的復位,可以跳過Security Boot和內核自檢的過程,從而加速啟動過程。
可選地啟用配置獨立的IVT(Interrupt Vector Table)。這需要配合REGFILE中最開始的兩個存儲字存放配置信息。REGFILE在Powerdown模式下仍能保存數據。
對內核進行例行自檢(Structural Core Self-Test,SCST)
這是為了配合實現功能安全等級ASIL-D標準,而進行的運行時測試。
根據BVT中的配置,在bootlaoder過程中啟用或者停用看門狗,以及對應的超時周期(HA01的WDG在默認情況下,使用來自于IPC的SIRC/4作為計數時鐘源)
BOOT ROM中的Bootloader執行過程
在HA01的RM手冊中,可以找到bootloader執行過程的示意圖。如圖x所示。
圖x BOOT ROM中的bootloader運行流程圖
從圖x中可以看到,芯片從上電啟動到用戶的main()函數,大體要經歷三個階段:
MCU Reset Phase
Boot Code Function
MCU App run Phase
芯片上電后(POR),根據REGFILE區域中的REG0的配置值,分別進入快速啟動流程(Fast Wakeup Boot Mode)或常規啟動流程(Normal Boot Mode)。
在快速啟動流程中:
解析BVT中預設的參數,以初始化系統時鐘。
從REGFILE->REG1寄存器中獲取快速啟動流程的應用程序入口地址(同常規啟動流程最終引導的應用程序入口地址可能不同)
查看IVT的地址并確保指定IVT的地址空間位于SRAM,后續將在用戶自行編寫的應用程序初始化階段存放中斷向量表。
跳轉到快速啟動流程的程序入口。
中間過程如果遇到任何異常,都會進入static mode(原地死循環)。
在常規啟動流程中:
解析BVT中預設的參數。
若BVT中配置啟用了Security Boot,則執行驗簽過程。
若BVT中配置啟用了SCST Test,則執行Cortex-M7處理器內核的自檢。
根據BVT中的參數,配置看門狗WDG外設模塊。
跳轉到常規啟動流程的程序入口。
中間過程如果遇到任何異常,都會進入static mode(原地死循環)。
快速啟動流程中不執行Security Boot和SCST Test過程,因此可以縮短啟動時間。但注意,快速啟動流程的應用程序入口同常規啟動的應用程序入口可能不是同一個。
BVT的數據結構
BVT保存了啟動過程中的很多關鍵參數,它本身位于pflash存儲區,0x0200_0000開始的一段內存空間,可由用戶在編寫應用程序時,創建一個結構體,然后在鏈接過程中將其安排至0x0200_0000地址。BVT的參數占用108個字節,但實際上卻需要預留2KB的空間,這是由于pflash的一個sector大小為2KB。用戶實際開發過程中,也可以調整linker file,避開0x0200_0000開始的一個sector,如此,可保持最近一次燒寫的可用的BVT配置不變。
手冊中列寫了BVT的字段定義,如圖x所示。
圖x 描述BVT的字段信息
從這里可以窺到一個有趣的設計,竟然提到了有CM7_0、CM7_1和CM7_2三個Cortex-M7處理器核心,并且每個核心有main和secondary兩個核心。從描述上看,這描述的是一對鎖步核(lockstep),并且每個核心都可以有獨立的應用起始地址(application start address),將來用于全并行地分別執行不同的應用程序。實際上,目前的HA01使用的是一個不可拆開的單鎖步核,故只有CM7_0_main可用。可以想見,在后續的產品規劃中,可能會出現最多3對鎖步核,如果進一步將鎖步核拆開,可以設計最多6個獨立的Cortex-M7核心。
BVT中0x4偏移地址上的Boot Configuration Word中進一步定義了啟動相關的配置項,如圖x中的表格所示。
圖x Boot Configuration Word的字段描述
這里提供了一個信息,運行bootloader程序使用了FIRC(96MHz)作為時鐘源,但可以通過CPDIVS設置1分頻或者2分頻。
這里還設計了很多功能的開關,例如看門狗、6個核心的獨立使能開關,SCST自檢功能。
這里還提到了serial security boot mode和normal boot mode,猜測前者可能就是驗簽的計算過程。
Practice
源碼中關于BVT的設計
用戶從SDK中導出的樣例工程,就有關于對BVT的定義,以及在鏈接腳本中專門分配的代碼段。
以hello_world工程為例,其中的secure_boot_YTM32B1HA0.h文件中有關于BVT類型的定義:
... #defineBVT_HEADER_SEG__attribute__((used))__attribute__((section(".bvt_header"))) ... /*! *@brieftheBVTstructuretypedefinition * *Implements:bvt_header_config_t_Class */ typedefstruct{ uint32_tbvt_marker;/*BVTmarker*/ uint32_tboot_config_word;/*Bootconfigurationword*/ uint32_tsbt_config_group_addr;/*securebootstartaddress*/ uint32_tlc_config;/*lifecycleconfiguration*/ uint32_tcm7_0_main_app_addr;/*CM7_0maincorestartaddress*/ uint32_tcm7_0_secondary_app_addr;/*ReservedforCM7_0_SECONDARY_APP_ADDR*/ uint32_tcm7_1_main_app_addr;/*ReservedforCM7_1_MAIN_APP_ADDR*/ uint32_tcm7_1_secondary_app_addr;/*ReservedforCM7_1_SECONDARY_APP_ADDR*/ uint32_tcm7_2_main_app_addr;/*ReservedforCM7_2_MAIN_APP_ADDR*/ uint32_tcm7_2_secondary_app_addr;/*ReservedforCM7_2_SECONDARY_APP_ADDR*/ uint32_tapp_wdg_timeout;/*timeoutsetoftheWDGwatchdogoftheapplicationcore*/ }bvt_header_config_t;
而在secure_boot_YTM32B1HA0.c文件中,有定義具體的結構體實例:
#defineBOOT_CONFIG_WORD(BVT_BCW_CPDIVS_SET(1)|CM7_0_M_EN) /*definethetimeoutofADGwatchdogoftheapplicationmaincore*/ #defineAPP_WDG_TIMEOUT(120000)/*10msrespectto12MHzSIRCasreferenceclock*/ /*Flasherasedstatus*/ #defineRESERVED(0xFFFFFFFF) /*BVTHeaderconfiguration*/ constbvt_header_config_tbvt_headerBVT_HEADER_SEG={ BVT_VALID_MARK,/*BVTmarker*/ BOOT_CONFIG_WORD,/*Bootconfigurationword*/ (uint32_t)&secure_boot_group,/*securebootstartaddress*/ RESERVED,/*lifecycleconfiguration*/ DEFAULT_START_ADDRESS,/*CM7maincorestartaddress*/ RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, APP_WDG_TIMEOUT,/*timeoutsetoftheWDGwatchdogoftheapplicationcore*/ };
此處注意,定義的bvt_header結構體將位于BVT_HEADER_SEG數據段內。其中DEFAULT_START_ADDRESS定義了同應用軟件約定的啟動地址,具體位于0x0200_0800。位于secure_boot_YTM32B1HA0.h文件中。
/*BVTvalidmarker*/ #defineBVT_VALID_MARK(0xA55AA55A) /*Defaultstartaddress*/ #defineDEFAULT_START_ADDRESS(0x02000800)
同時,在YTM32B1HA01_flash.sct文件中,也相應指定了BVT所占用的存儲空間(預留在0x0200_0000至0x0200_07FF,和應用程序的起始地址0x0200_0800:
#definem_bvt_start0x02000000 #definem_bvt_end0x020007FF #definem_bvt_sizem_bvt_end-m_bvt_start+1 #definem_interrupts_start0x02000800 #definem_interrupts_size0x00000400 。。。 LR_m_textm_bvt_start {;loadregionsize_region ER_m_text_2m_bvt_startFIXEDm_bvt_size { .ANY(.bvt_header) .ANY(.sb_config_group) .ANY(.sb_config_section) .ANY(.sb_cmac) } //vectors. VECTOR_ROMm_interrupts_startFIXEDm_interrupts_size { *(RESET+First) } //code. ER_m_textm_text_startFIXEDm_text_size { *(InRoot$$Sections) .ANY(+RO) } 。。。
當下載程序后,可以在memory的視圖中可以看到,0x0200_0000開始的位置,有存放關于BVT的配置信息。如圖x所示。
圖x 下載到HA01芯片中的BVT配置數據
在集成開發環境中調試
BOOT ROM + BVT相互配合,在HA01芯片內部實現了一個bootloader,但程序的起始地址也不再是常規默認的0x0000_0000,如此,當在集成開發環境中調試程序時,可能會需要指定一個程序入口點。實際上,bootloader的存在并不影響在載入調試環境時自動將程序斷點到main()函數:
在調試環境中,下載程序到芯片后復位,如果不顯式地執行入口程序地址,芯片會自動從bootloader開始執行,然后從BVT中取得用戶應用程序入口地址后,跳轉到用戶應用程序。確切地說,是進入到用戶程序的Reset_Handler函數,然后進入到main()函數。
大多數集成調試環境,會“智能”地在main()函數開始的位置打一個斷點,作為調試程序的開始,等待開發者發起進一步的調試動作。
這類似于以往開發者在有用戶自定義的bootloader的環境下開發application。
無論是Keil還是IAR,在集成開發環境內部啟動調試時,都可以自動執行上述流程至main()函數的斷點。但是,當使用Segger Ozone調試可執行文件時,由于默認會顯式指定一個入口地址,如果沒有合適的配置,默認從0x0000_0000開始,就會出現錯誤。如圖x。
圖x 在ozone中配置程序入口點
圖x 默認配置下載入調試出錯
從圖x中可以看到,Ozone默認從固件程序的開始,0x0200_0000,讀到了初始的PC和SP值,但這里的數據其實是BVT的內容,不是中斷向量表的項目。故會報錯。
此時,在配置初始載入點時,有幾種可行的配置,都可以實現正常調試:
Initial PC -> Read from Location -> 0x0100_0004, Initial Stack Pointer -> Read from Location -> 0x0100_0000。這種設置是從BOOT ROM中的bootloader開始啟動,然后引導到用戶應用程序。
Initial PC -> Read from Location -> 0x0200_0804, Initial Stack Pointer -> Read from Location -> 0x0200_0800。這種設置是跳過BOOT ROM中的bootloader啟動,直接從用戶應用程序啟動。
Initial PC -> Do not set, Initial Stack Pointer -> Do not set。這種設置是軟件工具不要多做,讓芯片的硬件機制起作用。此時芯片從BOOT ROM中的bootloader開始啟動,然后引導到用戶應用程序。
建議使用第三種方式,充分利用硬件機制,確保對芯片有最完整的初始化過程,也是最接近在芯片正常上電啟動的運行情況。
Conclusion
YTM32B1HA系列微控制器基于Arm Cortex-M7處理器內核,集成了BOOT ROM,并重新劃分了地址空間中的內存分配,這使得芯片上電之后的引導過程和用戶應用程序的存放地址發生了一些變化,對應地,使用調試軟件工具也需要做相應的適配操作,以避免出現異常的情況。
無論如何,BOOT ROM中的bootloader和BVT的配置,為應用帶來了一些新的功能,例如基于硬件計算引擎進行加速和加密的安全啟動過程、對多核心運行的管理等等。這為支持復雜的片上系統的奠定了一定的基礎,也是設計多核心SoC的啟動過程的一種可行的嘗試。
-
微控制器
+關注
關注
48文章
7552瀏覽量
151423 -
處理器
+關注
關注
68文章
19286瀏覽量
229842 -
內核
+關注
關注
3文章
1372瀏覽量
40290
原文標題:YTM32的HA系列微控制器啟動過程詳解
文章出處:【微信號:Ithingedu,微信公眾號:安芯教育科技】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論