查看: 1316|回复: 0

通用MCU Bootloader - KBOOT之IAP API

[复制链接]
  • TA的每日心情
    开心
    2024-3-26 15:16
  • 签到天数: 266 天

    [LV.8]以坛为家I

    3299

    主题

    6546

    帖子

    0

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    32024
    最后登录
    2024-4-25
    发表于 2020-1-15 13:23:51 | 显示全部楼层 |阅读模式
    通用MCU Bootloader - KBOOT之IAP API
       
           今天痞子衡给大家介绍的是飞思卡尔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特性:
    25.png
    一、API tree原型

      KBOOT中声明了如下一个名叫bootloader_tree_t的结构体来组织那些可被export出去的IP模块driver,结构体前4个成员记录了版本、版权以及Bootloader等信息,从第5个成员开始便是那些IP模块driver API,目前支持导出的模块API并不多,一共4个:Flash、AES、Kboot、USB。
    1. //! @brief Structure of version property.
    2. typedef union StandardVersion
    3. {
    4.     struct {
    5.         uint8_t bugfix;     //!< bugfix version [7:0]
    6.         uint8_t minor;      //!< minor version [15:8]
    7.         uint8_t major;      //!< major version [23:16]
    8.         char name;          //!< name [31:24]
    9.     };
    10.     uint32_t version;   //!< combined version numbers
    11. } standard_version_t;

    12. //! @brief Root of the bootloader API tree.
    13. //!
    14. //! An instance of this struct resides in read-only memory in the bootloader. It
    15. //! provides a user application access to APIs exported by the bootloader.
    16. //!
    17. //! @note The order of existing fields must not be changed.
    18. typedef struct BootloaderTree
    19. {
    20.     void (*runBootloader)(void *arg);            //!< Function to start the bootloader executing.
    21.     standard_version_t version;                  //!< Bootloader version number.
    22.     const char *copyright;                       //!< Copyright string.
    23.     const bootloader_context_t *runtimeContext;  //!< Pointer to the bootloader's runtime context.
    24.     const flash_driver_interface_t *flashDriver; //!< Flash driver API.
    25.     const aes_driver_interface_t *aesDriver;     //!< AES driver API.
    26.     const kb_interface_t *kbApi;                 //!< Bootloader API.
    27.     const usb_driver_interface_t *usbDriver;     //!< USB driver API.
    28. } bootloader_tree_t;
    复制代码
    在所有导出的模块driver API中,Flash driver API是使用最广泛的,其API原型如下(不同芯片中Flash driver API版本可能不一致,截止目前共有3个版本:F1.0.x、F1.1.x、F1.2.x):
    1. //! @brief Interface for the flash driver.
    2. typedef struct FlashDriverInterface {
    3. #if !defined(FLASH_API_TREE_1_0)
    4.     standard_version_t version; //!< flash driver API version number.
    5. #endif
    6.     status_t (*flash_init)(flash_driver_t * driver);
    7. #if defined(FLASH_API_TREE_1_0)
    8.     status_t (*flash_erase_all)(flash_config_t *config);
    9.     status_t (*flash_erase_all_unsecure)(flash_config_t *config);
    10.     status_t (*flash_erase)(flash_config_t *config, uint32_t start, uint32_t lengthInBytes);
    11. #else
    12.     status_t (*flash_erase_all)(flash_config_t *config, uint32_t key);
    13.     status_t (*flash_erase_all_unsecure)(flash_config_t *config, uint32_t key);
    14.     status_t (*flash_erase)(flash_config_t *config, uint32_t start, uint32_t lengthInBytes, uint32_t key);
    15. #endif
    16.     status_t (*flash_program)(flash_driver_t * driver, uint32_t start, uint32_t * src, uint32_t lengthInBytes);
    17.     status_t (*flash_get_security_state)(flash_driver_t * driver, flash_security_state_t * state);
    18.     status_t (*flash_security_bypass)(flash_driver_t * driver, const uint8_t * backdoorKey);
    19.     status_t (*flash_verify_erase_all)(flash_driver_t * driver, flash_margin_value_t margin);
    20.     status_t (*flash_verify_erase)(flash_driver_t * driver, uint32_t start, uint32_t lengthInBytes, flash_margin_value_t margin);
    21.     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);
    22.     status_t (*flash_get_property)(flash_driver_t * driver, flash_property_t whichProperty, uint32_t * value);
    23. #if (!defined(FLASH_API_TREE_1_0)) && (!defined(FLASH_API_TREE_1_1))
    24.     status_t (*flash_register_callback)(flash_driver_t * driver, flash_callback_t callback);
    25.     status_t (*flash_program_once)(flash_driver_t * driver, uint32_t index, uint32_t * src, uint32_t lengthInBytes);
    26.     status_t (*flash_read_once)(flash_driver_t * driver, uint32_t index, uint32_t * dst, uint32_t lengthInBytes);
    27.     status_t (*flash_read_resource)(flash_driver_t * driver, uint32_t start, uint32_t *dst, uint32_t lengthInBytes, flash_read_resource_option_t option);
    28. #endif
    29. } flash_driver_interface_t;
    复制代码
    下表列出了所有含ROM空间的芯片中Flash driver API的版本:
    24.png
    Note: 模块driver API设计必须满足几个条件:一、API里不能使用全局变量;二、模块IRQHandler不能直接当做API


    二、API tree位置

      声明好了bootloader_tree_t结构体原型以及各IP模块driver API原型,下一步便是在KBOOT中定义如下常量g_bootloaderTree以创建对象分配内存(不同芯片中g_bootloaderTree版本可能不一致,下面是用于K80芯片上的K1.3.0版)。
    1. //! @brief Static API tree.
    2. const bootloader_tree_t g_bootloaderTree =
    3. {
    4.     .runBootloader = bootloader_user_entry,
    5.     .version = {
    6.             .name = kBootloader_Version_Name,
    7.             .major = kBootloader_Version_Major,
    8.             .minor = kBootloader_Version_Minor,
    9.             .bugfix = kBootloader_Version_Bugfix
    10.         },
    11.     .copyright = bootloaderCopyright,
    12.     .runtimeContext = &g_bootloaderContext,
    13.     .flashDriver = &g_flashDriverInterface,
    14.     .aesDriver = &g_aesInterface
    15. };
    复制代码
    只要找到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地址。
    1.    MODULE  ?cstartup

    2.         ;; Forward declaration of sections.
    3.         SECTION CSTACK:DATA:NOROOT(3)
    4.         SECTION .intvec:CODE:NOROOT(2)

    5.         EXTERN  g_bootloaderTree
    6.         PUBLIC  __vector_table
    7.         PUBLIC  __vector_table_0x1c

    8.         DATA

    9. __vector_table
    10.         DCD     sfe(CSTACK)
    11.         DCD     Reset_Handler

    12.         DCD     NMI_Handler
    13.         DCD     HardFault_Handler
    14.         DCD     MemManage_Handler
    15.         DCD     BusFault_Handler
    16.         DCD     UsageFault_Handler
    17. __vector_table_0x1c
    18.         DCD     g_bootloaderTree
    19.         DCD     0
    20.         DCD     0
    21.         DCD     0
    22.         DCD     SVC_Handler
    23.         DCD     DebugMon_Handler
    24.         DCD     0
    25.         DCD     PendSV_Handler
    26.         DCD     SysTick_Handler
    27.         ;; ...
    复制代码
    三、调用API的方法
      KBOOT中的ROM API调用方法非常简单,以K80芯片中Flash driver API调用为例,首先需要按以下步骤定义s_flashInterface指针:
    1. #define BOOTLOADER_TREE_LOCATION (0x1c00001cul)

    2. #define BOOTLOADER_API_TREE_POINTER (*(bootloader_tree_t **)BOOTLOADER_TREE_LOCATION)

    3. static const flash_driver_interface_t *s_flashInterface = BOOTLOADER_API_TREE_POINTER->flashDriver;
    复制代码
     有了s_flashInterface指针便可以随意访问Flash driver API:
    1. const uint32_t test_program_buffer[2] = { 0x01234567, 0x89abcdef };
    2. flash_config_t flashInstance;

    3. s_flashInterface->flash_init(&flashInstance);
    4. s_flashInterface->flash_erase(&flashInstance, 0x8000, 0x1000);
    5. s_flashInterface->flash_program(&flashInstance, 0x8000, (uint32_t *)test_program_buffer, 8);
    复制代码





    作者:痞子衡

    签到签到
    回复

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /4 下一条

    Archiver|手机版|小黑屋|恩智浦技术社区

    GMT+8, 2024-4-25 15:43 , Processed in 0.114094 second(s), 20 queries , MemCache On.

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.

    快速回复 返回顶部 返回列表