痞子衡嵌入式:飞思卡尔Kinetis系列MCU启动那些事(10)- KBOOT特性(可靠升级)
大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家介绍的是飞思卡尔Kinetis系列MCU的KBOOT之可靠升级(Reliable Update)特性。
所谓可靠升级机制,即在更新Application过程中不论发生任何异常情况(通信异常、系统断电等)都能保证系统中至少有一份可用的Application用于恢复启动,保证系统的正常运行。可靠升级是任何鲁棒的Bootloader架构都应该要有的特性。作为一个健全的Bootloader架构,KBOOT中当然包含可靠升级特性。今天痞子衡就为大家介绍KBOOT中的Reliable Update特性:
一、可靠升级基本策略
可靠升级基本策略其实很简单,在Flash里划分2个区,主分区用于存放待启动的Application,备份区用于临时存放新更新的Application,下载时永远只往备份区存最新的Application,这样即使下载过程中发生意外,也仅导致备份区里的Application不完整,不影响主分区里的Application正常运行。仅当备份区里的Application经过Bootloader验证是完整的(详见痞子衡之前写过的 《KBOOT特性(完整性检测)》 一文,通过完整性检测即认为Application是完整的),Bootloader才会启动更新工作,将主分区里Application擦除,然后将备份区里的Application拷贝到主分区,最后擦除备份区里的Application,在这更新过程中不用担心意外,因为任何时候Flash里都至少有一个Application是完整的。
KBOOT里的可靠升级特性就是按照上述基本策略实现的,但是我们知道KBOOT架构适用于上百种Kinetis芯片,上百种芯片特性各异,但就可靠升级这一特性而言,Kinetis芯片被分为三类:
- 第一类:不含ROM,且Flash没有SWAP特性,如MKL25Z128
- 第二类:不含ROM,但Flash含有SWAP特性,如MK65FN2M
- 第三类:含ROM,无论Flash是否含有SWAP,如MKE18F512
KBOOT可靠升级在三类Kinetis芯片上的实现是有区别的。对于第一类,Flash起始地址存放固定的Bootloader,Main/Backup App紧随其后,这也是最常见的情形;对于第二类,因为Flash有SWAP特性,所以Flash被严格分为两个大小相等的Block,SWAP特性可以直接逻辑上交换这两个Block,因此两个Block除了各自存放Application之外还分别存放了Bootloader;对于第三类,这就比较简单了,Bootloader在独立的ROM区域,不占用Flash空间,因此Flash直接均分2等份,一份放Main App,另一份放Backup App就行。
二、可靠升级具体实现
上一节讲过,根据Kinetis芯片Flash是否含有SWAP特性,可靠升级的实现是不同的。如果Flash有SWAP特性,我们称之为硬可靠升级;反之,如果Flash不含SWAP特性,我们称之为软可靠升级。在介绍可靠升级具体实现逻辑之前,痞子衡先为大家比较一下软/硬可靠升级的差异:
比较项目 | 软可靠升级 | 硬可靠升级 |
---|---|---|
适用芯片 | 所有Kinetis | 仅含SWAP特性的Kinetis |
Flash内容分布 | Bootloader + Main App + Backup App | Main Bootloader + Main App + Backup Bootloader + Backup App |
备份区App存放地址 | 灵活定义 | 固定的 |
能否保留2份App | 不可以 | 可以 |
2.1 触发方式
不管是硬可靠升级还是软可靠升级都有两种触发方式,一种是上电启动自触发,上电Bootloader运行时会尝试执行一次可靠升级,这种触发方式是被动地且是一次性的;另一种是命令式触发,即用户通过blhost.exe发送reliable-update命令主动执行可靠升级,这种方式可重复多次。
2.1.1 命令式触发
命令式触发是触发可靠升级操作的第一选择,备份区下载完最新的Application后应紧跟着发送可靠升级命令完成新旧Application的更新。reliable-update命令格式在输入blhost -?命令后可以看到:
reliable-update命令仅有一个addr参数,对于硬可靠升级,这个addr参数是swap indicator地址(想了解swap indicator的意义需要查看Kinetis手册FTFx一节),如果是首次启动硬可靠升级,swap indicator地址可任意设置,如果已经启动过硬可靠升级,swap indicator已经存在芯片IFR里,此时addr必须与已存的swap indicator相一致;对于软可靠升级,这个addr参数即备份区Application的存放起始地址(如果addr为0,则使用Bootloader里预定义的backup app存放地址)。
2.1.2 上电自触发
上电自触发方式存在的原因是,用户在备份区下载完Application之后可能会忘了主动触发可靠升级,或者在执行主动可靠升级的过程中发生了异常,那么系统下一次启动时应主动做一次可靠升级,确保将备份区最新的Application拷贝到主分区去运行。下图是自触发可靠升级在Bootloader启动流程中的位置:
2.2 主逻辑
无论是上电自触发还是命令式触发,在Bootloader里其实都是调用的如下函数bootloader_reliable_update_as_requested(),命令式触发传入的参数值是(kReliableUpdateOption_Swap, addr),上电自触发传入的参数值是(kReliableUpdateOption_Normal, 0)
void bootloader_reliable_update_as_requested(reliable_update_option_t option, uint32_t address)
{
uint32_t backupApplicationBase;
#if BL_IS_HARDWARE_SWAP_ENABLED
// 仅对于硬可靠升级,才区分option参数的差异
uint32_t swapIndicatorAddress = address;
if (option == kReliableUpdateOption_Normal)
{
// 检测主分区App是否有效,如果有效,则不进行可靠升级
uint32_t mainApplicationBase = get_application_base(kSpecifiedApplicationType_Main);
if (is_specified_application_valid(mainApplicationBase))
{
update_reliable_update_status(kStatus_ReliableUpdateStillInMainApplication);
return;
}
else
{
// 检测flash swap状态看其是否处于Ready状态,如果是,则从IFR里读取已存swap indicator值
status_t result = get_swap_indicator_address_if_system_is_in_ready(&swapIndicatorAddress);
if (result != kStatus_FLASH_Success)
{
update_reliable_update_status(kStatus_ReliableUpdateSwapSystemNotReady);
return;
}
}
}
backupApplicationBase = get_application_base(kSpecifiedApplicationType_Backup);
#else
// 获取备份区App的存放地址
backupApplicationBase = (address == 0) ? get_application_base(kSpecifiedApplicationType_Backup) : address;
#endif // BL_IS_HARDWARE_SWAP_ENABLED
// 检测备份区App的BCA配置是否有效,BCA有效是进行可靠升级的前提
if (!is_reliable_update_active(backupApplicationBase))
{
update_reliable_update_status(kStatus_ReliableUpdateInacive);
}
else
{
// 仅当备份区App通过了完整性检测,才会进行可靠升级
if (is_specified_application_valid(backupApplicationBase))
{
#if BL_IS_HARDWARE_SWAP_ENABLED
status_t status = hardware_reliable_update(swapIndicatorAddress);
#else
status_t status = software_reliable_update(backupApplicationBase);
#endif // BL_IS_HARDWARE_SWAP_ENABLED
update_reliable_update_status(status);
}
else
{
update_reliable_update_status(kStatus_ReliableUpdateBackupApplicationInvalid);
}
}
}
2.2.1 软可靠升级流程
软可靠升级流程如下,首先根据不同触发方式获取备份区App的存放地址,然后检测备份区App是否合法(包含BCA,且通过完整性验证),一旦备份区App被验证是合法的,Bootloader会擦除主分区App并将备份区App拷贝到主分区,最后再擦除备份区App。有朋友会疑问,为何最后要擦除备份区App,因为当前的软可靠升级实现在自触发方式下第一件事就是去验证备份区App是否有效,如果备份区App不擦除的话,每次上电都会做一次擦除和更新操作,会损耗Flash寿命。
上述流程就是KBOOT 2.0里的软可靠升级的实现逻辑。那么这个流程有没有改进空间呢?其实是有的。如果我们在App的BCA区域增加一个版本号,那么就可以做到在Flash里保留两份App。此时Bootloader下载App时不再需要提供存放地址,Bootloader自动解析App的版本号,并用这个最新的App替换Flash里版本最低的App。而Bootloader启动时永远寻找当前Flash里版本最高的App去执行。
Note: 改进后的软可靠升级有一个注意点,即Flash里XIP App并不是与位置无关的,因此两份App的链接文件根据存放位置不同,链接起始地址是不同的。
2.2.2 硬可靠升级流程
硬可靠升级相比软可靠升级,在流程看起来更复杂,因为硬可靠升级涉及Flash的SWAP特性,不过硬可靠升级不具通用性,因此痞子衡不打算详细解释其流程,感兴趣的自己研究下面的流图。
2.3 配置宏和状态码
对于KBOOT 2.0来说,目前仅有MK65默认使能了可靠升级,如果想要在其他芯片上也使能这一特性,需要在对应芯片的bootloader_config.h里修改/增加如下三个宏:
- BL_FEATURE_RELIABLE_UPDATE: 设为1则使能可靠升级特性
- BL_FEATURE_HARDWARE_SWAP_UPDATE: 设为1则为硬可靠升级,0则为软可靠升级
- BL_BACKUP_APP_START: 预定义的备份区App存放地址
在使用reliable-update命令的过程中会返回执行结果状态码,以及可以用get-property获得当前可靠升级状态机的状态,一共有如下8个状态码:
至此,飞思卡尔Kinetis系列MCU的KBOOT之可靠升级(Reliable Update)痞子衡便介绍完毕了,掌声在哪里~~~
最后欢迎关注痞子衡个人微信公众号【痞子衡嵌入式】,一个专注嵌入式技术的公众号,跟着痞子衡一起玩转嵌入式。
衡杰(痞子衡),目前就职于某全球顶级半导体原厂MCU系统部门,担任高级嵌入式系统应用工程师。
专栏内所有文章的转载请注明出处:http://www.cnblogs.com/henjay724/
与痞子衡进一步交流或咨询业务合作请发邮件至 hengjie1989@foxmail.com
可以关注痞子衡的Github主页 https://github.com/JayHeng,有很多好玩的嵌入式项目。
关于专栏文章有任何疑问请直接在博客下面留言,痞子衡会及时回复免费(划重点)答疑。
痞子衡邮箱已被私信挤爆,技术问题不推荐私信,坚持私信请先扫码付款(5元起步)再发。