你們好,我是痞子衡,是正經搞技術的痞子。今天痞子衡給你們介紹的是飛思卡爾Kinetis系列MCU的KBOOT之ROM API特性。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特性:微信
KBOOT中聲明瞭以下一個名叫bootloader_tree_t的結構體來組織那些可被export出去的IP模塊driver,結構體前4個成員記錄了版本、版權以及Bootloader等信息,從第5個成員開始即是那些IP模塊driver API,目前支持導出的模塊API並很少,一共4個:Flash、AES、Kboot、USB。app
//! @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):ide
//! @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的版本:ui
- Note: 模塊driver API設計必須知足幾個條件:1、API裏不能使用全局變量;2、模塊IRQHandler不能直接當作API
聲明好了bootloader_tree_t結構體原型以及各IP模塊driver API原型,下一步即是在KBOOT中定義以下常量g_bootloaderTree以建立對象分配內存(不一樣芯片中g_bootloaderTree版本可能不一致,下面是用於K80芯片上的K1.3.0版)。this
//! @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地址。.net
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 ;; ...
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特性痞子衡便介紹完畢了,掌聲在哪裏~~~code
文章會同時發佈到個人 博客園主頁、CSDN主頁、微信公衆號 平臺上。
微信搜索"痞子衡嵌入式"或者掃描下面二維碼,就能夠在手機上第一時間看了哦。