KBOOT的ROM API特性主要存在于ROM Bootloader形态中,KBOOT内部內建了一些Kinetis内部IP子產品driver,這些IP子產品driver首要目的是用于實作KBOOT的功能,但由于這些IP子產品driver會随着KBOOT一起被固化在ROM空間裡,是以如果這些IP driver能夠被外部(主要是運作于Flash中的Application)調用,那麼肯定會節省Application代碼空間,這麼看起來将ROM Bootloader裡的一些IP driver以API的形式export出去是很有意義的,這麼有意義的事,KBOOT當然是會做的。
大家好,我是痞子衡,是正經搞技術的痞子。今天痞子衡給大家介紹的是飛思卡爾Kinetis系列MCU的KBOOT之ROM API特性。
KBOOT的ROM API特性主要存在于ROM Bootloader形态中,KBOOT内部內建了一些Kinetis内部IP子產品driver,這些IP子產品driver首要目的是用于實作KBOOT的功能,但由于這些IP子產品driver會随着KBOOT一起被固化在ROM空間裡,是以如果這些IP driver能夠被外部(主要是運作于Flash中的Application)調用,那麼肯定會節省Application代碼空間,這麼看起來将ROM Bootloader裡的一些IP driver以API的形式export出去是很有意義的,這麼有意義的事,KBOOT當然是會做的。下面痞子衡給大家介紹KBOOT裡的ROM API特性:

一、API tree原型
KBOOT中聲明了如下一個名叫bootloader_tree_t的結構體來組織那些可被export出去的IP子產品driver,結構體前4個成員記錄了版本、版權以及Bootloader等資訊,從第5個成員開始便是那些IP子產品driver API,目前支援導出的子產品API并不多,一共4個:Flash、AES、Kboot、USB。
//! @brief Structure of version property. typedef union StandardVersion { struct { uint8_t bugfix; //!< bugfix version [7:0] uint8_t minor; //!< minor version [15:8] uint8_t major; //!< major version [23:16] char name; //!< name [31:24] }; uint32_t version; //!< combined version numbers } standard_version_t; //! @brief Root of the bootloader API tree. //! //! An instance of this struct resides in read-only memory in the bootloader. It //! provides a user application access to APIs exported by the bootloader. //! //! @note The order of existing fields must not be changed. typedef struct BootloaderTree { void (*runBootloader)(void *arg); //!< Function to start the bootloader executing. standard_version_t version; //!< Bootloader version number. const char *copyright; //!< Copyright string. const bootloader_context_t *runtimeContext; //!< Pointer to the bootloader's runtime context. const flash_driver_interface_t *flashDriver; //!< Flash driver API. const aes_driver_interface_t *aesDriver; //!< AES driver API. const kb_interface_t *kbApi; //!< Bootloader API. const usb_driver_interface_t *usbDriver; //!< USB driver API. } bootloader_tree_t;
在所有導出的子產品driver API中,Flash driver API是使用最廣泛的,其API原型如下(不同晶片中Flash driver API版本可能不一緻,截止目前共有3個版本:F1.0.x、F1.1.x、F1.2.x):
//! @brief Interface for the flash driver. typedef struct FlashDriverInterface { #if !defined(FLASH_API_TREE_1_0) standard_version_t version; //!< flash driver API version number. #endif status_t (*flash_init)(flash_driver_t * driver); #if defined(FLASH_API_TREE_1_0) status_t (*flash_erase_all)(flash_config_t *config); status_t (*flash_erase_all_unsecure)(flash_config_t *config); status_t (*flash_erase)(flash_config_t *config, uint32_t start, uint32_t lengthInBytes); #else status_t (*flash_erase_all)(flash_config_t *config, uint32_t key); status_t (*flash_erase_all_unsecure)(flash_config_t *config, uint32_t key); status_t (*flash_erase)(flash_config_t *config, uint32_t start, uint32_t lengthInBytes, uint32_t key); #endif status_t (*flash_program)(flash_driver_t * driver, uint32_t start, uint32_t * src, uint32_t lengthInBytes); status_t (*flash_get_security_state)(flash_driver_t * driver, flash_security_state_t * state); status_t (*flash_security_bypass)(flash_driver_t * driver, const uint8_t * backdoorKey); status_t (*flash_verify_erase_all)(flash_driver_t * driver, flash_margin_value_t margin); status_t (*flash_verify_erase)(flash_driver_t * driver, uint32_t start, uint32_t lengthInBytes, flash_margin_value_t margin); status_t (*flash_verify_program)(flash_driver_t * driver, uint32_t start, uint32_t lengthInBytes, const uint8_t * expectedData, flash_margin_value_t margin, uint32_t * failedAddress, uint32_t * failedData); status_t (*flash_get_property)(flash_driver_t * driver, flash_property_t whichProperty, uint32_t * value); #if (!defined(FLASH_API_TREE_1_0)) && (!defined(FLASH_API_TREE_1_1)) status_t (*flash_register_callback)(flash_driver_t * driver, flash_callback_t callback); status_t (*flash_program_once)(flash_driver_t * driver, uint32_t index, uint32_t * src, uint32_t lengthInBytes); status_t (*flash_read_once)(flash_driver_t * driver, uint32_t index, uint32_t * dst, uint32_t lengthInBytes); status_t (*flash_read_resource)(flash_driver_t * driver, uint32_t start, uint32_t *dst, uint32_t lengthInBytes, flash_read_resource_option_t option); #endif } flash_driver_interface_t;
下表列出了所有含ROM空間的晶片中Flash driver API的版本:
- Note: 子產品driver API設計必須滿足幾個條件:一、API裡不能使用全局變量;二、子產品IRQHandler不能直接當做API
二、API tree位置
聲明好了bootloader_tree_t結構體原型以及各IP子產品driver API原型,下一步便是在KBOOT中定義如下常量g_bootloaderTree以建立對象配置設定記憶體(不同晶片中g_bootloaderTree版本可能不一緻,下面是用于K80晶片上的K1.3.0版)。
//! @brief Static API tree. const bootloader_tree_t g_bootloaderTree = { .runBootloader = bootloader_user_entry, .version = { .name = kBootloader_Version_Name, .major = kBootloader_Version_Major, .minor = kBootloader_Version_Minor, .bugfix = kBootloader_Version_Bugfix }, .copyright = bootloaderCopyright, .runtimeContext = &g_bootloaderContext, .flashDriver = &g_flashDriverInterface, .aesDriver = &g_aesInterface };
隻要找到g_bootloaderTree位址,便可以通路到那些IP子產品driver API,現在的問題是如何找到g_bootloaderTree位址?我們知道在KBOOT工程中,如果不在連結檔案裡明确指定g_bootloaderTree位址,連結器會随機配置設定一個位址來存放g_bootloaderTree,這會導緻在不同晶片中g_bootloaderTree位址是不一樣的;但即使強制指定g_bootloaderTree連結位址,如果ROM空間起始位址不一定是從0x1c000000開始,那麼還是難以做到g_bootloaderTree位址統一。到底該怎麼解決這個問題?KBOOT使用了一個巧妙的方法,下面是KBOOT工程的startup檔案(IAR版),KBOOT将g_bootloaderTree的位址放到了中斷向量表第8個向量的位置處(該向量為ARM Cortex-M未定義的系統向量),是以隻要知道了ROM空間的起始位址,那麼偏移0x1c處開始的4bytes便是g_bootloaderTree位址。
MODULE ?cstartup ;; Forward declaration of sections. SECTION CSTACK:DATA:NOROOT(3) SECTION .intvec:CODE:NOROOT(2) EXTERN g_bootloaderTree PUBLIC __vector_table PUBLIC __vector_table_0x1c DATA __vector_table DCD sfe(CSTACK) DCD Reset_Handler DCD NMI_Handler DCD HardFault_Handler DCD MemManage_Handler DCD BusFault_Handler DCD UsageFault_Handler __vector_table_0x1c DCD g_bootloaderTree DCD 0 DCD 0 DCD 0 DCD SVC_Handler DCD DebugMon_Handler DCD 0 DCD PendSV_Handler DCD SysTick_Handler ;; ...
三、調用API的方法
KBOOT中的ROM API調用方法非常簡單,以K80晶片中Flash driver API調用為例,首先需要按以下步驟定義s_flashInterface指針:
#define BOOTLOADER_TREE_LOCATION (0x1c00001cul) #define BOOTLOADER_API_TREE_POINTER (*(bootloader_tree_t **)BOOTLOADER_TREE_LOCATION) static const flash_driver_interface_t *s_flashInterface = BOOTLOADER_API_TREE_POINTER->flashDriver;
有了s_flashInterface指針便可以随意通路Flash driver API:
const uint32_t test_program_buffer[2] = { 0x01234567, 0x89abcdef }; flash_config_t flashInstance; s_flashInterface->flash_init(&flashInstance); s_flashInterface->flash_erase(&flashInstance, 0x8000, 0x1000); s_flashInterface->flash_program(&flashInstance, 0x8000, (uint32_t *)test_program_buffer, 8);
至此,飛思卡爾Kinetis系列MCU的KBOOT之ROM API特性痞子衡便介紹完畢了,掌聲在哪裡~~~
歡迎訂閱
文章會同時釋出到我的 部落格園首頁、CSDN首頁、微信公衆号 平台上。
微信搜尋"痞子衡嵌入式"或者掃描下面二維碼,就可以在手機上第一時間看了哦。
最後歡迎關注痞子衡個人微信公衆号【痞子衡嵌入式】,一個專注嵌入式技術的公衆号,跟着痞子衡一起玩轉嵌入式。
衡傑(痞子衡),目前就職于恩智浦MCU系統部門,擔任嵌入式系統應用工程師。
專欄内所有文章的轉載請注明出處:http://www.cnblogs.com/henjay724/
與痞子衡進一步交流或咨詢業務合作請發郵件至 [email protected]
可以關注痞子衡的Github首頁 https://github.com/JayHeng,有很多好玩的嵌入式項目。
關于專欄文章有任何疑問請直接在部落格下面留言,痞子衡會及時回複免費(劃重點)答疑。
痞子衡郵箱已被私信擠爆,技術問題不推薦私信,堅持私信請先掃碼付款(5元起步)再發。