
嵌入式固件驱动开发【免费下载链接】DAPLink项目地址https://gitcode.com/gh_mirrors/da/DAPLink点击查看免费下载DAPLink 的接口固件Interface Firmware支持将引导加载程序Bootloader固件与自身捆绑在一起并在接口固件首次启动时自动完成引导加载程序的更新。本文以 docs/BOOTLOADER_UPDATES.md 为核心脉络结合仓库源码bootloader_update.c、iap_flash_intf.c、main_interface.c 等解析其工作流程、失电安全设计、版本校验与降级防护规则并给出在具体板卡上启用该机制的完整配置方法。读完本文你将掌握 DAPLink 引导加载程序随接口固件同包更新的原理、如何为板卡开启该特性以及它在更新过程中的三大安全防线与三类使用限制。一、机制总览引导加载程序与接口固件同包更新在传统固件升级流程中引导加载程序通常需要借助调试器或独立的刷写工具单独更新用户操作繁琐且容易出错。DAPLink 改变了这一模式DAPLink 能够把引导加载程序固件与接口固件捆绑在一起并在接口固件首次启动时应用一次引导加载程序更新。这样一来引导加载程序的更新就可以与接口固件的更新在同一时刻完成用户无需任何特殊操作。这一定位由 source/daplink/interface/bootloader_update.c 的注释明确阐述/** * file bootloader_update.c * brief Logic to perform a bootloader update when enabled */从调用时序看更新检查发生在接口固件启动流程的早期阶段。在 main_interface.c 中// Update versions and IDs info_init(); // Update bootloader if it is out of date bootloader_check_and_update(); // USB usbd_init();即接口固件完成info_init()读取并校验固件版本、CRC 等元信息之后、USB 初始化之前就调用bootloader_check_and_update()。这保证了引导加载程序更新在设备对外呈现为可用调试器/MSC 设备之前完成用户看到的是一个“已经就绪”的 DAPLink。二、启用方式定义DAPLINK_BOOTLOADER_UPDATE要为某块板卡或接口电路HIC启用引导加载程序更新只需定义宏DAPLINK_BOOTLOADER_UPDATE#define DAPLINK_BOOTLOADER_UPDATE定义该宏之后即可走常规的发布流程详见 developers guide为所有目标构建固件。该宏在源码中扮演“开关”角色见 bootloader_update.c#if !defined(DAPLINK_BOOTLOADER_UPDATE) #define DAPLINK_BOOTLOADER_UPDATE 0 #endif #if DAPLINK_BOOTLOADER_UPDATE // The bootloader must be built first or this header will not be found #include bootloader_image.c #else //DAPLINK_BOOTLOADER_UPDATE static const unsigned int image_start 0; static const unsigned int image_size 0; static const char image_data[1]; #endif //DAPLINK_BOOTLOADER_UPDATE这里有一个非常关键的构建依赖引导加载程序必须先构建否则bootloader_image.c这个头文件不会存在。该文件由构建系统的后处理脚本自动生成见 tools/post_build_script.pydef post_build_script(input_file, output_file, board_idNone, ...): ... output_file_c output_format_file .c output_file_c_generic join(dirname(output_file), bootloader_image.c)脚本在构建引导加载程序时把其二进制镜像连同起始地址、大小一起转写为 C 数组image_start、image_size、image_data供接口固件构建时直接嵌入。这正是“捆绑”的实现方式——引导加载程序的镜像被静态包含进接口固件运行时由接口固件负责将其写回引导区。未定义该宏时接口固件中嵌入的是空镜像image_size 0bootloader_check_and_update()会因update_present为假而直接返回不做任何更新动作。2.1 引导加载程序构建的配套宏从 records/daplink/bootloader.yaml 可以看到引导加载程序构建的公共宏定义common: macros: - DAPLINK_BL - DAPLINK_BUILD_KEY0x9B939D93 # DAPLINK_BUILD_KEY_BLDAPLINK_BUILD_KEY_BL0x9B939D93与接口固件的DAPLINK_BUILD_KEY_IF0x9B939E8F定义于 daplink.h是固件身份校验的关键凭据后文会再次涉及。三、安全更新设计向量表的“临时接管”更新引导加载程序有一个固有的风险接口固件在更新过程中需要擦除并重写向量表Vector Table而向量表是设备上电后第一条指令所在的位置。如果擦除后、写回前设备断电芯片将没有任何有效的向量表可执行直接进入不可引导nonbootable的砖机状态。3.1 失电窗口最小化策略文档给出的策略是在正式更新前接口固件先把引导加载程序的向量表替换为自己的向量表。这样在批量加载引导加载程序主体期间向量表始终有效即使发生失电设备也能正常启动只是启动到接口固件而非引导加载程序。完整的更新流程如下加粗步骤为设备绝对不能失电的临界区擦除引导向量表并把接口固件的向量表编程到该位置逐扇区擦除并编程引导加载程序的新固件擦除引导向量表并把新引导加载程序的向量表编程到该位置。流程对应的核心实现在 source/daplink/drag-n-drop/iap_flash_intf.c 中。该文件实现了flash_intf_iap_protected——一个“受保护的 IAP 闪存接口”其声明与默认弱实现分别在 flash_intf.h 和 flash_intf.c__WEAK const flash_intf_t *const flash_intf_iap_protected 0;启用引导加载程序更新的平台则提供真实实现iap_flash_intf.cconst flash_intf_t *const flash_intf_iap_protected flash_intf;3.2 临界擦写critical_erase_and_program临界区的擦写由critical_erase_and_program()完成iap_flash_intf.cstatic error_t critical_erase_and_program(uint32_t addr, const uint8_t *data, uint32_t size) { uint32_t iap_status; if (size DAPLINK_MIN_WRITE_SIZE) { util_assert(0); return ERROR_INTERNAL; } // CRITICAL SECTION BELOW HERE! // If something goes wrong with either // the erase or write then the device // will no longer be bootable. // Erase the first sector iap_status flash_erase_sector(addr); ... // Program the interfaces vector table iap_status flash_program_page(addr, size, (uint8_t *)data); ... }源码注释用大写明确警告该区域内一旦擦除或写入出错设备将不再可引导。函数先擦除首扇区再立刻编程“接口固件的向量表”正是文档所述三步流程中的第 1 步与第 3 步的落地点。3.3 扇区擦除与页写入的拦截逻辑为了让普通拖放drag-n-drop刷写流程能够安全地更新引导区iap_flash_intf.c对写入与擦除做了“拦截intercept”处理页写入拦截intercept_page_write()iap_flash_intf.c只允许写入更新区[DAPLINK_ROM_UPDATE_START, DAPLINK_ROM_UPDATE_START DAPLINK_ROM_UPDATE_SIZE)落在更新区首扇区内的数据先被暂存到sector_buf并同步累计 CRC32当收到更新区的最后一个页时校验镜像末尾内嵌的 CRCERROR_BL_UPDT_BAD_CRC表示 CRC 不符随后编程该页并调用critical_erase_and_program(DAPLINK_ROM_UPDATE_START, sector_buf, DAPLINK_SECTOR_SIZE)把暂存的首扇区含接口向量表写回更新区起始处。扇区擦除拦截intercept_sector_erase()iap_flash_intf.c当擦除目标恰好是DAPLINK_ROM_UPDATE_START时改为执行critical_erase_and_program(addr, (uint8_t *)DAPLINK_ROM_IF_START, DAPLINK_MIN_WRITE_SIZE)——擦除后立即把接口固件开头的向量表编程进该位置保证擦除瞬间过后设备依然具备有效向量表。需要说明的是只有daplink_is_interface()为真即运行的是接口固件而非引导加载程序时拦截逻辑才会生效iap_flash_intf.c。3.4 内存布局约束向量表“先换后写”的策略之所以成立依赖于 DAPLink 固定且连续的内存分区布局。daplink.h 中的编译期断言强制这些约束// ROM check COMPILER_ASSERT(DAPLINK_ROM_BL_START DAPLINK_ROM_START); COMPILER_ASSERT(DAPLINK_ROM_IF_START DAPLINK_ROM_IF_SIZE DAPLINK_ROM_CONFIG_USER_START); COMPILER_ASSERT(DAPLINK_ROM_CONFIG_USER_START DAPLINK_ROM_CONFIG_USER_SIZE DAPLINK_ROM_START DAPLINK_ROM_SIZE);即 ROM 从引导加载程序区开始紧接接口固件区再是用户配置区三区连续、无空隙、恰好占满全部 ROM。具体的偏移量由各板卡的_bl.c文件以编译期断言固化例如k20dx_bl.cCOMPILER_ASSERT(DAPLINK_ROM_IF_START KB(32));——接口固件从 0x800032 KB处加载kl27z_microbit_bl.cDAPLINK_ROM_IF_START KB(32)且DAPLINK_ROM_IF_SIZE (KB(128) - KB(32) - KB(1))。注释“Warning - changing the interface start will break backwards compatibility”直白地提醒改动接口固件加载偏移会破坏向后兼容。四、更新前的三项安全检查接口固件在执行引导加载程序更新前会依次通过三道检查bootloader_update.c 中的bootloader_check_and_update()void bootloader_check_and_update(void) { int same; error_t ret; bool update_present image_size 0; if (!update_present) { return; } if (info_get_bootloader_present() (info_get_bootloader_version() DAPLINK_VERSION)) { // Bootloader is more recent than the one we have so // dont change it return; } if (!interface_image_valid()) { // The interface is corrupt so dont attempt // to apply the update util_assert(0); return; } same memcmp((void*)image_start, image_data, image_size) 0; if (!same) { ret flash_manager_init(flash_intf_iap_protected); ... ret flash_manager_data(image_start, (const uint8_t*)image_data, image_size); ... ret flash_manager_uninit(); ... } }4.1 检查一不降级版本比较if (info_get_bootloader_present() (info_get_bootloader_version() DAPLINK_VERSION)) { // Bootloader is more recent than the one we have so // dont change it return; }如果当前引导加载程序具有有效签名且其版本号大于接口固件内嵌副本的版本DAPLINK_VERSION则接口固件不会替换它。这是文档明确承诺的行为接口固件不会降级引导加载程序。若当前引导加载程序拥有有效签名且版本高于接口固件中的副本接口固件将不会替换它。“有效签名”的判断来自info_get_bootloader_present()info.c它依次校验引导区大小非零DAPLINK_ROM_BL_SIZE ! 0、引导区可读、build_key等于DAPLINK_BUILD_KEY_BL、hic_id与当前 HIC 一致——任一不满足都视为“不存在有效引导加载程序”。4.2 检查二接口固件自检 CRCstatic bool interface_image_valid() { uint32_t stored_crc 0; uint32_t computed_crc; if (flash_is_readable(DAPLINK_ROM_IF_START DAPLINK_ROM_IF_SIZE - 4, 4)) { stored_crc *(uint32_t *)(DAPLINK_ROM_IF_START DAPLINK_ROM_IF_SIZE - 4); } computed_crc info_get_crc_interface(); return computed_crc stored_crc; }接口固件会对自身镜像做一次 CRC32 校验把镜像末尾 4 字节中存储的 CRC 与info_get_crc_interface()现算出的 CRC 比对。若发现自身已损坏则放弃引导加载程序更新同时util_assert(0)会在大容量存储MSC设备上呈现一条断言信息。CRC 的计算发生在info_crc_compute()info.c它对引导区、接口区、用户配置区分别用crc32计算各自剔除末尾 4 字节的 CRC 槽位。4.3 检查三镜像比对跳过重复更新same memcmp((void*)image_start, image_data, image_size) 0; if (!same) { ... }接口固件把内嵌副本与当前引导加载程序逐字节比对若二者相同则不做任何写操作。这避免了无意义的擦写也降低了每次启动时的损耗与风险窗口。三道检查全部通过后才经由flash_manager_init(flash_intf_iap_protected)→flash_manager_data(...)→flash_manager_uninit()完成整个更新使用的正是上文所述的“受保护 IAP 接口”。五、注意事项与使用限制5.1 固定加载偏移0x8000DAPLink 引导加载程序对接口固件的加载位置有固定要求——典型情况下接口固件从 ROM 起始偏移 0x8000 处加载对应 32 KB见各板卡_bl.c中的COMPILER_ASSERT(DAPLINK_ROM_IF_START KB(32))。如果更新到一个偏移不同的引导加载程序则现有的接口固件将无法继续使用必须改用为新偏移构建的接口固件。5.2 不支持降级与第三方引导加载程序该机制不支持降级也不支持加载第三方引导加载程序。若确有此类需求只能通过调试器刷写或构建 DAPLink 的自定义版本。5.3 LPC11U35 无引导加载程序LPC11U35 接口本身没有引导加载程序仓库中不存在 lpc11u35 的_bl板卡文件其板卡源码为 swdap-lpc11u35.c因此该接口上无法使用引导加载程序更新机制。5.4 更新状态的查看方式更新是否发生、当前引导加载程序版本与 CRC 等信息都可以通过接口固件挂载出的DETAILS.TXT查看。相关字段在 vfs_user.c 中生成例如Daplink Mode: Interface Interface Version: V Bootloader Version: xxxx Git SHA: ... USB Interfaces: MSD, CDC, HID Bootloader CRC: ... Interface CRC: ...其中 “Bootloader Version” 仅在DAPLINK_ROM_BL_SIZE ! 0且引导加载程序存在时输出vfs_user.c是快速确认更新是否成功落盘的直观手段。六、小结DAPLink 的引导加载程序自动更新机制本质上是把“引导加载程序镜像内嵌进接口固件 首启动时自动刷写 向量表临时接管”三者组合起来启用为板卡定义DAPLINK_BOOTLOADER_UPDATE并保证先构建引导加载程序生成bootloader_image.c再构建接口固件安全通过三步流程换入接口向量表 → 逐扇区写入 → 换回新引导向量表把不可引导的失电窗口压缩到最小并辅以 IAP 拦截、CRC 校验等手段防线版本不降级、接口自检 CRC 不过则放弃、镜像相同则跳过边界固定加载偏移、不支持降级/第三方引导加载程序、LPC11U35 无此能力。理解了这些约束与实现细节无论是为自有板卡接入该机制还是排查引导加载程序更新失败的问题都能做到有据可依。赞分享嵌入式固件驱动开发【免费下载链接】DAPLink项目地址https://gitcode.com/gh_mirrors/da/DAPLink点击查看免费下载相关推荐如何快速开始Syncfusion DashboardReact Syncfusion环境搭建教程如何快速开始Syncfusion DashboardReact Syncfusion环境搭建教程 想要快速构建功能强大的React管理仪表盘吗Syncf深入理解 inconshreveable/go-update 实现安全的Go程序自更新机制深入理解 inconshreveable/go update 实现安全的Go程序自更新机制 概述 inconshreveable/go update 是一个专门开发工具UEFI安全启动终极指南shim引导加载器深度解析与实战应用UEFI安全启动终极指南shim引导加载器深度解析与实战应用 在现代计算机系统中 UEFI安全启动 已成为保护系统免受恶意软件侵害的关键技术。而 shim引操作系统应用安全上一篇PyPTO Tile Framework 测试工程架构与设计指南UT/ST 目录规划、CMake 编排与执行加速体系下一篇XiaoMusic小爱音箱播放全网音乐的 Docker 部署教程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考