你們好,我是痞子衡,是正經搞技術的痞子。今天痞子衡給你們介紹的是i.MXRTxxx系列ROM API設計細節。html
痞子衡以前寫過兩篇文章 《利用i.MXRT1xxx系列ROM提供的FlexSPI driver API可輕鬆IAP》、《其實i.MXRT1050,1020,1015系列ROM也提供了FlexSPI driver API》 基本把i.MXRT1xxx全系列的ROM API及其FlexSPI NOR驅動設計都講清楚了,其實i.MXRTxxx系列的ROM API設計跟i.MXRT1xxx系列的設計思路差很少(其實本就是同一個恩智浦研發小組負責的),僅有一些微小區別,本文痞子衡主要就是點出那些區別。api
ROM API代碼首先是在BootROM裏,BootROM代碼是出廠前固化在ROM區域的。由於架構設計的關係,i.MXRTxxx系列和i.MXRT1xxx系列的ROM區域在系統內存裏的映射地址不一樣。安全
下表是i.MXRTxxx系列表明型號i.MXRT500的部分系統內存映射,能夠看到ROM區域起始地址是0x03000000(非安全域)。目前i.MXRTxxx都是Cortex-M33內核,支持TrustZone特性,因此0x13000000也是ROM起始地址(安全域),爲了通用性,咱們認0x03000000就能夠了,這個地址在安全狀態和非安全狀態下都能被訪問。微信
下表是i.MXRT1xxx系列表明型號i.MXRT1060的部分系統內存映射,能夠看到ROM區域起始地址是0x00200000。i.MXRT1xxx系列都是Cortex-M7內核,沒有TrustZone特性,不存在i.MXRTxxx上那樣的兩種狀態域下的地址。架構
在i.MXRT1xxx系列ROM API介紹的文章裏,痞子衡介紹過g_bootloaderTree地址值被複制了一份放在了BootROM中斷向量表第8個向量的位置處(該向量爲ARMv7-M架構下未定義的系統向量),所以讀取0x0020001c處開始的4bytes便能找到i.MXRT1xxx系列的g_bootloaderTree。函數
可是因爲i.MXRTxxx是Cortex-M33內核,屬於ARMv8-M架構,從下圖中能夠看出ARMv8-M架構下中斷向量表第8個向量是SecureFault,已經被定義了,所以BootROM把g_bootloaderTree地址值放到了第9個向量的位置處(該向量爲ARMv8-M架構下未定義的系統向量),故讀取0x03000020處開始的4bytes才能找到i.MXRTxxx系列的g_bootloaderTree(這種方式在實際API調用中並不可取,至於緣由嘛,先賣個關子)。flex
下面是i.MXRT500 BootROM工程的startup文件(IAR版),g_bootloaderTree確實在第9個向量處:ui
MODULE ?cstartup ;; Forward declaration of sections. SECTION CSTACK:DATA:NOROOT(3) SECTION .intvec:CODE:NOROOT(2) EXTERN __iar_program_start EXTERN g_bootloaderTree PUBLIC __vector_table PUBLIC __vector_table_0x1c DATA __vector_table DCD sfe(CSTACK) DCD Reset_Handler DCD DefaultISR DCD HardFault_Handler DCD DefaultISR DCD DefaultISR DCD UsageFault_Handler __vector_table_0x1c DCD SecureFault_Handler DCD g_bootloaderTree DCD 0 DCD 0 DCD SVC_Handler DCD DefaultISR DCD 0 DCD DefaultISR DCD SysTick_Handler ;; ...
下面是i.MXRTxxx系列ROM API原型定義及其實例(適用i.MXRT500/600),基本形式跟i.MXRT1xxx差很少,可是API功能更豐富,除了FlexSPI NOR驅動,還有iap api、USB low-level driver、otp driver等(咱們知道,i.MXRTxxx與LPC系列同根同源,LPC系列ROM裏通常都會集成不少經典SDK驅動,好比內部flash、low power驅動,有了這些穩定的驅動API,LPC系列的用戶手冊裏甚至都會省去這些IP的寄存器介紹,直接就是API的介紹)。.net
typedef struct { void (*runBootloader)(void *arg); uint32_t version; const char *copyright; const bootloader_context_t *runtimeContext; const kb_interface_t *kbApi; const usb_driver_interface_t *usbDriver; const USBD_API_T *lpcUsbDriver; const flexspi_nor_flash_driver_t *flexspiNorDriver; const ocotp_driver_t *otpDriver; const skboot_authenticate_interface_t *skbootAuthenticate; } bootloader_api_entry_t; //! @brief Static API tree. __root const bootloader_api_entry_t g_bootloaderTree @".rom_api_tree_section" = { .runBootloader = bootloader_user_entry, .version = MAKE_VERSION('K', 3, 0, 0), .copyright = "Copyright 2019 NXP.", .runtimeContext = &g_bootloaderContext, .kbApi = &g_romApiInterface, .usbDriver = &g_usbDriverInterface, .flexspiNorDriver = &g_flexspiNorFlashDriverInterface, .otpDriver = &g_otpDriverInterface, .skbootAuthenticate = &g_skbootAuthenticateInterface, };
i.MXRT1xxx系列ROM API實例g_bootloaderTree都是讓連接器自由連接的,所以每一個具體型號的實際ROM API連接地址沒有一致的規律可循(這也是爲何要在中斷向量表裏固定位置統一保存一份),而這點在i.MXRTxxx上有了改進,i.MXRTxxx裏將g_bootloaderTree放到了 .rom_api_tree_section 段裏,在連接文件裏將該段固定連接在ROM區域最後4KB處(BootROM代碼沒有把所有ROM空間用盡)。架構設計
下面是i.MXRTxxx BootROM源文件中g_bootloaderTree的定義,加了段修飾。此外還有額外的k_romcrc,標示API實例區域的結束。
__root const bootloader_api_entry_t g_bootloaderTree @".rom_api_tree_section" = { .runBootloader = bootloader_user_entry, .version = MAKE_VERSION('K', 3, 0, 0), .copyright = "Copyright 2019 NXP.", .runtimeContext = &g_bootloaderContext, // ... }; __root const uint32_t k_romcrc @".romcrc" = 0xdeadbeef;
下面是i.MXRTxxx連接文件(IAR工程)中 .rom_api_tree_section 段的處理(i.MXRT500型號示例,ROM空間是192KB)。你可能好奇爲啥ROM_API_TREE_xx等值是放在0x13000000開始的安全域ROM空間映射,BootROM屬於上電啓動第一級,負責芯片系統的安全和啓動,固然是工做在安全狀態下,能夠訪問安全域地址空間。
define symbol __ICFEDIT_region_ROM_API_TREE_start__ = 0x1302f000; define symbol __ICFEDIT_region_ROM_API_TREE_end__ = 0x1302f0ff; define symbol __ICFEDIT_region_ROM_CRC_CHECKSUM_start__ = 0x1302fffc; define symbol __ICFEDIT_region_ROM_CRC_CHECKSUM_end__ = 0x1302ffff; define region ROM_API_TREE_region = mem:[from __ICFEDIT_region_ROM_API_TREE_start__ to __ICFEDIT_region_ROM_API_TREE_end__]; define region ROM_CRC_CHECKSUM = mem:[from __ICFEDIT_region_ROM_CRC_CHECKSUM_start__ to __ICFEDIT_region_ROM_CRC_CHECKSUM_end__]; place in ROM_API_TREE_region { section .rom_api_tree_section }; place in ROM_CRC_CHECKSUM { section .romcrc };
基於上面的設計,你纔會在i.MXRT500參考手冊裏Non-Secure Boot ROM章節看到以下ROM API地址及結構信息圖(圖中僅標了經常使用的API功能函數),實際ROM API調用時,App的執行其實都是通過ROM引導和認證的,App中既能夠訪問安全域地址(0x1302f000)來調用API,也能夠訪問非安全域地址(0x0302f000)來調用API。
最後再來回答前面賣的關子,爲何i.MXRTxxx系列經過BootROM中斷向量表第9個向量值來訪問ROM API這種方式並不可取?其實從BootROM煞費苦心地將g_bootloaderTree固定連接在ROM區域最後4KB處,你就能看出其用意。若是你掛上調試器直接訪問i.MXRTxxx的ROM區域前20KB的空間,你會發現沒法訪問,在App裏AHB方式讀這個區域,也會直接產生HardFault,由於BootROM裏作了特殊設計故意隱藏了前20KB空間,這個空間裏存放了BootROM想要保護的數據和代碼,至於內容是啥,純屬機密,恕不奉告,哈哈。
至此,i.MXRTxxx系列ROM API設計細節痞子衡便介紹完畢了,掌聲在哪裏~~~
文章會同時發佈到個人 博客園主頁、CSDN主頁、知乎主頁、微信公衆號 平臺上。
微信搜索"痞子衡嵌入式"或者掃描下面二維碼,就能夠在手機上第一時間看了哦。