痞子衡嵌入式:飛思卡爾Kinetis系列MCU啓動那些事(11)- KBOOT特性(ROM API)


  你們好,我是痞子衡,是正經搞技術的痞子。今天痞子衡給你們介紹的是飛思卡爾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特性:微信

1、API tree原型

  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

2、API tree位置

  聲明好了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
		;; ...

3、調用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特性痞子衡便介紹完畢了,掌聲在哪裏~~~code

歡迎訂閱

文章會同時發佈到個人 博客園主頁CSDN主頁微信公衆號 平臺上。

微信搜索"痞子衡嵌入式"或者掃描下面二維碼,就能夠在手機上第一時間看了哦。

相關文章
相關標籤/搜索