固件OTA升级方案设计:差分升级、断电保护与回滚——双分区、签名验证
文章目录

每日一句正能量
成熟的情绪管理,是允许情绪自然存在,任它穿过身体。
成熟不是压抑或控制情绪,而是不再与情绪对抗。像对待天气一样,允许愤怒、悲伤、恐惧来临,感受它们在身体里的流动,然后看着它们离开。这种“不粘着”的态度,才是真正的情绪自由。
一、前言:为什么OTA是嵌入式产品的"生命线"?
在物联网时代,设备部署后无法像手机App那样随时召回维修。一个部署在偏远山区的智能电表、一辆行驶中的智能汽车、一台深海作业的水下机器人——这些设备的固件缺陷一旦暴露,远程OTA(Over-The-Air)升级就是唯一的修复手段。
然而,嵌入式OTA面临服务器端软件无法想象的风险:
| 风险场景 | 后果 | 发生概率 |
|---|---|---|
| 升级过程中断电 | 设备变"砖",无法启动 | 5-10%(恶劣环境) |
| 网络传输丢包 | 固件损坏,签名验证失败 | 1-3%(弱网环境) |
| 恶意固件刷入 | 设备被控制,数据泄露 | 安全攻击 |
| 版本回滚攻击 | 降级到存在漏洞的旧版本 | 安全攻击 |
| 存储空间不足 | 升级失败,原有固件被破坏 | 资源受限设备 |
一个工业级OTA方案必须同时解决五大核心问题:差分升级(节省流量)、断电保护(防变砖)、签名验证(防篡改)、版本防回滚(防降级攻击)、自动回滚(故障自愈)。本文将从Flash分区设计到Bootloader实现,完整讲解一套经过量产验证的OTA架构。
二、双分区OTA系统整体架构

2.1 核心设计原则
双分区(A/B分区) 是OTA系统的基石。系统始终保留两个完整的固件副本:一个正在运行(Active),一个用于接收更新(Inactive)。这种设计从根本上解决了"升级过程中断电变砖"的问题——即使新固件写入失败,Bootloader仍可启动旧固件。
| 组件 | 功能 | 大小(典型) |
|---|---|---|
| Bootloader | 分区选择、签名验证、启动跳转 | 16-32KB |
| Partition Info | 启动标志、版本信息、校验和 | 4KB |
| App A | 当前运行固件 | 可用Flash的一半 |
| App B | 待更新固件 | 可用Flash的一半 |
| Backup Data | OTA进度、配置、日志 | 16-32KB |
2.2 Flash分区布局

/* flash_layout.h - Flash分区定义 */
#ifndef FLASH_LAYOUT_H
#define FLASH_LAYOUT_H
#include <stdint.h>
/* Flash总大小: 1MB (STM32F4xx) */
#define FLASH_TOTAL_SIZE (1024 * 1024)
#define FLASH_BASE_ADDR 0x08000000
#define FLASH_SECTOR_SIZE 4096 /* 4KB扇区 */
/* ============================================================================
* 分区定义
* ============================================================================ */
/* Bootloader: 0x08000000 - 0x08007FFF (32KB) */
#define BOOTLOADER_START 0x08000000
#define BOOTLOADER_SIZE (32 * 1024)
#define BOOTLOADER_END (BOOTLOADER_START + BOOTLOADER_SIZE)
/* Partition Info: 0x08008000 - 0x08008FFF (4KB) */
#define PARTITION_INFO_START 0x08008000
#define PARTITION_INFO_SIZE FLASH_SECTOR_SIZE
#define PARTITION_INFO_END (PARTITION_INFO_START + PARTITION_INFO_SIZE)
/* App A: 0x08009000 - 0x08080FFF (480KB) */
#define APP_A_START 0x08009000
#define APP_A_SIZE (480 * 1024)
#define APP_A_END (APP_A_START + APP_A_SIZE)
/* App B: 0x08081000 - 0x08100FFF (480KB) */
#define APP_B_START 0x08081000
#define APP_B_SIZE (480 * 1024)
#define APP_B_END (APP_B_START + APP_B_SIZE)
/* Backup Data: 0x08101000 - 0x08108FFF (32KB) */
#define BACKUP_DATA_START 0x08101000
#define BACKUP_DATA_SIZE (32 * 1024)
#define BACKUP_DATA_END (BACKUP_DATA_START + BACKUP_DATA_SIZE)
/* OTA Temp: 0x08109000 - 0x0810FFFF (28KB) */
#define OTA_TEMP_START 0x08109000
#define OTA_TEMP_SIZE (28 * 1024)
#define OTA_TEMP_END (OTA_TEMP_START + OTA_TEMP_SIZE)
/* 验证地址合法性 */
#define IS_VALID_APP_ADDR(addr) \\
(((addr) >= APP_A_START && (addr) < APP_A_END) || \\
((addr) >= APP_B_START && (addr) < APP_B_END))
#endif /* FLASH_LAYOUT_H */
三、差分升级:从256KB到12KB的魔法

3.1 差分算法选型
| 算法 | 压缩率 | 内存需求 | 解压速度 | 许可证 | 适用场景 |
|---|---|---|---|---|---|
| bsdiff | 极高 | 高(17x旧文件) | 中等 | BSD | 大文件、内存充裕 |
| HDiffPatch | 高 | 低(5x旧文件) | 快 | MIT | 嵌入式首选 |
| xdelta3 | 中等 | 中等 | 快 | GPL | 流式处理 |
| MTF | 低 | 极低 | 极快 | 自定义 | 极简设备 |
对于RAM仅64KB的嵌入式设备,HDiffPatch是最佳选择——它在压缩率和内存占用之间取得了最佳平衡。
3.2 差分包生成(服务器端)
#!/bin/bash
# generate_ota_package.sh - 差分包生成脚本
set -euo pipefail
OLD_FIRMWARE="${1:-firmware_v2.1.0.bin}"
NEW_FIRMWARE="${2:-firmware_v2.2.0.bin}"
OUTPUT_DIR="${3:-ota_output}"
PRIVATE_KEY="${4:-ota_signing_key.pem}"
VERSION_OLD=$(echo "$OLD_FIRMWARE" | grep -oP 'v\d+\.\d+\.\d+')
VERSION_NEW=$(echo "$NEW_FIRMWARE" | grep -oP 'v\d+\.\d+\.\d+')
mkdir -p "$OUTPUT_DIR"
echo "=========================================="
echo "OTA Package Generation"
echo "Old: $VERSION_OLD -> New: $VERSION_NEW"
echo "=========================================="
# 1. 计算新旧固件的哈希
echo "[1/6] Computing hashes..."
OLD_HASH=$(sha256sum "$OLD_FIRMWARE" | cut -d' ' -f1)
NEW_HASH=$(sha256sum "$NEW_FIRMWARE" | cut -d' ' -f1)
echo " Old hash: $OLD_HASH"
echo " New hash: $NEW_HASH"
# 2. 生成差分包
echo "[2/6] Generating diff package..."
hdiffz -p-8 -s-64 "$OLD_FIRMWARE" "$NEW_FIRMWARE" "$OUTPUT_DIR/diff_${VERSION_OLD}_${VERSION_NEW}.hdiff"
DIFF_SIZE=$(stat -c%s "$OUTPUT_DIR/diff_${VERSION_OLD}_${VERSION_NEW}.hdiff")
echo " Diff size: $DIFF_SIZE bytes"
# 3. 验证差分包(解压测试)
echo "[3/6] Verifying diff package..."
hpatchz "$OLD_FIRMWARE" "$OUTPUT_DIR/diff_${VERSION_OLD}_${VERSION_NEW}.hdiff" "$OUTPUT_DIR/reconstructed.bin"
if ! diff -q "$NEW_FIRMWARE" "$OUTPUT_DIR/reconstructed.bin" > /dev/null; then
echo "ERROR: Reconstructed firmware mismatch!"
exit 1
fi
echo " Verification passed"
# 4. 构建OTA元数据
echo "[4/6] Building metadata..."
cat > "$OUTPUT_DIR/ota_metadata.json" <<EOF
{
"version_old": "$VERSION_OLD",
"version_new": "$VERSION_NEW",
"hash_old": "$OLD_HASH",
"hash_new": "$NEW_HASH",
"size_old": $(stat -c%s "$OLD_FIRMWARE"),
"size_new": $(stat -c%s "$NEW_FIRMWARE"),
"size_diff": $DIFF_SIZE,
"compression": "hdiffz",
"target_device": "STM32F407VG",
"release_date": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
"changelog": "See CHANGELOG.md"
}
EOF
# 5. 打包
echo "[5/6] Packaging..."
tar -czf "$OUTPUT_DIR/ota_package_${VERSION_NEW}.tar.gz" -C "$OUTPUT_DIR" \
ota_metadata.json \
diff_${VERSION_OLD}_${VERSION_NEW}.hdiff
# 6. 签名
echo "[6/6] Signing package..."
openssl dgst -sha256 -sign "$PRIVATE_KEY" \
-out "$OUTPUT_DIR/ota_package_${VERSION_NEW}.tar.gz.sig" \
"$OUTPUT_DIR/ota_package_${VERSION_NEW}.tar.gz"
# 验证签名
openssl dgst -sha256 -verify ota_signing_pubkey.pem \
-signature "$OUTPUT_DIR/ota_package_${VERSION_NEW}.tar.gz.sig" \
"$OUTPUT_DIR/ota_package_${VERSION_NEW}.tar.gz"
echo "=========================================="
echo "OTA package generated successfully"
echo "Output: $OUTPUT_DIR/ota_package_${VERSION_NEW}.tar.gz"
echo "Size reduction: $(stat -c%s "$NEW_FIRMWARE") -> $DIFF_SIZE ($(echo "scale=1; $DIFF_SIZE * 100 / $(stat -c%s "$NEW_FIRMWARE")" | bc)%)"
echo "=========================================="
3.3 设备端差分解压
/* ota_diff_patch.c - 设备端差分解压 */
#include "ota_diff_patch.h"
#include "flash_layout.h"
#include "log_api.h"
/* HDiffPatch库适配层 */
#include "hpatch.h"
/* 解压上下文 */
typedef struct {
uint8_t temp_buffer[OTA_TEMP_SIZE]; /* 临时缓冲区 */
uint32_t temp_used;
const uint8_t* old_firmware; /* 指向旧固件的指针 */
uint32_t old_size;
uint32_t write_addr; /* 当前写入地址(分区B) */
uint32_t bytes_written;
} PatchContext_t;
static PatchContext_t s_patch_ctx = {0};
/* Flash写入回调(HDiffPatch库调用) */
static int Patch_WriteCallback(hpatch_uint32_t offset,
const unsigned char* data,
hpatch_size_t len) {
/* 计算目标地址 */
uint32_t addr = APP_B_START + offset;
/* 边界检查 */
if (addr + len > APP_B_END) {
LOG_ERROR("OTA", "Write beyond partition B boundary");
return -1;
}
/* 按页写入Flash(假设页大小256B) */
for (hpatch_size_t i = 0; i < len; i += 256) {
hpatch_size_t chunk = (len - i < 256) ? (len - i) : 256;
/* 检查是否需要擦除(跨扇区边界) */
uint32_t page_addr = addr + i;
if ((page_addr % FLASH_SECTOR_SIZE) == 0) {
HAL_StatusTypeDef status = HAL_FLASHEx_Erase_Sector(
GetSectorNumber(page_addr),
FLASH_VOLTAGE_RANGE_3
);
if (status != HAL_OK) {
LOG_ERROR("OTA", "Flash erase failed at 0x%08X", page_addr);
return -1;
}
}
/* 写入数据 */
for (hpatch_size_t j = 0; j < chunk; j += 4) {
uint32_t word = *((uint32_t*)(data + i + j));
HAL_StatusTypeDef status = HAL_FLASH_Program(
FLASH_TYPEPROGRAM_WORD,
page_addr + j,
word
);
if (status != HAL_OK) {
LOG_ERROR("OTA", "Flash program failed at 0x%08X", page_addr + j);
return -1;
}
}
}
s_patch_ctx.bytes_written += len;
return 0;
}
/* 读取旧固件回调 */
static int Patch_ReadOldCallback(hpatch_uint32_t offset,
unsigned char* out_data,
hpatch_size_t len) {
if (offset + len > s_patch_ctx.old_size) {
return -1;
}
memcpy(out_data, s_patch_ctx.old_firmware + offset, len);
return 0;
}
/* 主解压函数 */
ErrorCode_t OTA_ApplyDiffPatch(const uint8_t* diff_data, uint32_t diff_size,
const uint8_t* old_firmware, uint32_t old_size) {
LOG_INFO("OTA", "Starting diff patch application");
LOG_INFO("OTA", "Old size: %lu, Diff size: %lu", old_size, diff_size);
/* 初始化上下文 */
s_patch_ctx.old_firmware = old_firmware;
s_patch_ctx.old_size = old_size;
s_patch_ctx.write_addr = APP_B_START;
s_patch_ctx.bytes_written = 0;
/* 解锁Flash */
HAL_FLASH_Unlock();
/* 调用HDiffPatch解压 */
hpatch_TStreamInput diff_stream;
diff_stream.streamImport = NULL;
diff_stream.streamSize = diff_size;
diff_stream.read = DiffStreamRead; /* 实现略 */
hpatch_TStreamInput old_stream;
old_stream.streamImport = NULL;
old_stream.streamSize = old_size;
old_stream.read = Patch_ReadOldCallback;
hpatch_compressedDiffInfo diff_info;
if (!hpatch_compressedDiffInfo_init(&diff_info, &diff_stream)) {
LOG_ERROR("OTA", "Invalid diff package header");
HAL_FLASH_Lock();
return ERR_OTA_INVALID_PACKAGE;
}
/* 执行解压 */
hpatch_TCovers covers;
if (!hpatch_TCovers_init(&covers, &diff_stream, &diff_info)) {
LOG_ERROR("OTA", "Failed to init covers");
HAL_FLASH_Lock();
return ERR_OTA_PATCH_FAILED;
}
/* 解压并写入分区B */
int result = hpatch_decompress_mem(&covers, &old_stream,
&diff_stream, &diff_info,
Patch_WriteCallback,
s_patch_ctx.temp_buffer,
sizeof(s_patch_ctx.temp_buffer));
HAL_FLASH_Lock();
if (result != 0) {
LOG_ERROR("OTA", "Patch application failed: %d", result);
/* 清除分区B(防止启动损坏固件) */
OTA_ClearPartitionB();
return ERR_OTA_PATCH_FAILED;
}
LOG_INFO("OTA", "Patch applied successfully, written %lu bytes",
s_patch_ctx.bytes_written);
return ERR_OK;
}
四、断电保护与断点续传

4.1 OTA进度持久化
/* ota_progress.h - OTA进度管理 */
#ifndef OTA_PROGRESS_H
#define OTA_PROGRESS_H
#include <stdint.h>
#include <stdbool.h>
#define OTA_PROGRESS_MAGIC 0x4F544150 /* "OTAP" */
#define OTA_PROGRESS_VERSION 1
/* OTA状态枚举 */
typedef enum {
OTA_STATE_IDLE = 0,
OTA_STATE_DOWNLOADING,
OTA_STATE_DOWNLOADED,
OTA_STATE_PATCHING,
OTA_STATE_PATCHED,
OTA_STATE_VERIFYING,
OTA_STATE_VERIFIED,
OTA_STATE_COMMITTING,
OTA_STATE_COMMITTED,
OTA_STATE_ROLLBACK,
OTA_STATE_FAILED
} OtaState_t;
/* 进度记录结构(存储于Backup Data区) */
typedef struct __attribute__((packed)) {
uint32_t magic; /* 魔数,用于验证记录有效性 */
uint16_t version; /* 记录格式版本 */
uint32_t target_version; /* 目标版本号 */
uint32_t total_size; /* 固件总大小 */
uint32_t received_size; /* 已接收大小 */
uint32_t current_crc32; /* 当前CRC32 */
OtaState_t state; /* 当前状态 */
uint8_t target_partition; /* 目标分区: 0=A, 1=B */
uint16_t chunk_size; /* 分块大小 */
uint32_t last_timestamp; /* 最后更新时间戳 */
uint32_t download_retries; /* 下载重试次数 */
uint8_t reserved[16]; /* 保留 */
uint32_t crc; /* 本记录的CRC校验 */
} OtaProgressRecord_t;
/* 初始化进度记录 */
void OTA_ProgressInit(void);
/* 读取进度 */
bool OTA_ProgressRead(OtaProgressRecord_t* record);
/* 原子更新进度 */
bool OTA_ProgressUpdate(const OtaProgressRecord_t* record);
/* 清除进度(升级完成或失败后) */
void OTA_ProgressClear(void);
/* 检查是否有未完成的升级 */
bool OTA_HasPendingUpdate(void);
/* 恢复未完成的升级 */
ErrorCode_t OTA_ResumeUpdate(void);
#endif /* OTA_PROGRESS_H */
/* ota_progress.c - 进度管理实现 */
#include "ota_progress.h"
#include "flash_layout.h"
#include "log_api.h"
/* 使用双缓冲确保原子性 */
#define PROGRESS_SLOT_0_ADDR BACKUP_DATA_START
#define PROGRESS_SLOT_1_ADDR (BACKUP_DATA_START + sizeof(OtaProgressRecord_t))
static uint8_t s_progress_buffer[sizeof(OtaProgressRecord_t)];
/* 计算记录CRC */
static uint32_t Progress_CalculateCRC(const OtaProgressRecord_t* record) {
/* 排除crc字段本身 */
return CRC32_Calculate((const uint8_t*)record,
sizeof(OtaProgressRecord_t) - sizeof(uint32_t));
}
/* 验证记录有效性 */
static bool Progress_IsValid(const OtaProgressRecord_t* record) {
if (record->magic != OTA_PROGRESS_MAGIC) {
return false;
}
if (record->version != OTA_PROGRESS_VERSION) {
return false;
}
uint32_t calc_crc = Progress_CalculateCRC(record);
if (calc_crc != record->crc) {
LOG_WARN("OTA", "Progress record CRC mismatch: calc=0x%08X, stored=0x%08X",
calc_crc, record->crc);
return false;
}
return true;
}
/* 原子写入(双缓冲 + 顺序写入) */
bool OTA_ProgressUpdate(const OtaProgressRecord_t* record) {
/* 1. 准备数据 */
OtaProgressRecord_t write_record = *record;
write_record.last_timestamp = HAL_GetTick();
write_record.crc = Progress_CalculateCRC(&write_record);
/* 2. 确定写入槽位(交替使用两个槽位) */
static uint8_t s_current_slot = 0;
uint32_t target_addr = (s_current_slot == 0) ? PROGRESS_SLOT_0_ADDR : PROGRESS_SLOT_1_ADDR;
uint32_t backup_addr = (s_current_slot == 0) ? PROGRESS_SLOT_1_ADDR : PROGRESS_SLOT_0_ADDR;
s_current_slot ^= 1; /* 切换槽位 */
/* 3. 先擦除目标槽位 */
HAL_FLASH_Unlock();
FLASH_EraseInitTypeDef erase_init = {
.TypeErase = FLASH_TYPEERASE_SECTORS,
.Sector = GetSectorNumber(target_addr),
.NbSectors = 1,
.VoltageRange = FLASH_VOLTAGE_RANGE_3
};
uint32_t sector_error = 0;
HAL_StatusTypeDef status = HAL_FLASHEx_Erase(&erase_init, §or_error);
if (status != HAL_OK) {
LOG_ERROR("OTA", "Failed to erase progress sector");
HAL_FLASH_Lock();
return false;
}
/* 4. 写入新记录(按字写入) */
const uint32_t* src = (const uint32_t*)&write_record;
for (size_t i = 0; i < sizeof(OtaProgressRecord_t); i += 4) {
status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, target_addr + i, src[i/4]);
if (status != HAL_OK) {
LOG_ERROR("OTA", "Failed to write progress at offset %d", i);
HAL_FLASH_Lock();
return false;
}
}
HAL_FLASH_Lock();
/* 5. 验证写入 */
OtaProgressRecord_t verify_record;
memcpy(&verify_record, (void*)target_addr, sizeof(OtaProgressRecord_t));
if (!Progress_IsValid(&verify_record)) {
LOG_ERROR("OTA", "Progress write verification failed");
return false;
}
LOG_DEBUG("OTA", "Progress updated: state=%d, received=%lu/%lu",
write_record.state, write_record.received_size, write_record.total_size);
return true;
}
/* 恢复未完成的升级 */
ErrorCode_t OTA_ResumeUpdate(void) {
OtaProgressRecord_t record;
if (!OTA_ProgressRead(&record)) {
return ERR_OK; /* 无待处理升级 */
}
LOG_INFO("OTA", "Resuming update from state %d, received %lu/%lu",
record.state, record.received_size, record.total_size);
switch (record.state) {
case OTA_STATE_DOWNLOADING:
/* 从断点继续下载 */
return OTA_DownloadResume(&record);
case OTA_STATE_DOWNLOADED:
/* 已下载完成,开始打补丁 */
return OTA_StartPatching(&record);
case OTA_STATE_PATCHING:
/* 补丁中断,需要重新开始(补丁不支持断点) */
LOG_WARN("OTA", "Patch interrupted, restarting from download");
record.state = OTA_STATE_DOWNLOADING;
record.received_size = 0;
OTA_ProgressUpdate(&record);
return OTA_DownloadResume(&record);
case OTA_STATE_PATCHED:
case OTA_STATE_VERIFYING:
/* 验证中断,重新验证 */
return OTA_VerifyFirmware(record.target_partition);
default:
LOG_WARN("OTA", "Unexpected state %d, clearing progress", record.state);
OTA_ProgressClear();
return ERR_OK;
}
}
4.2 断电保护写入策略
/* ota_flash_write.c - 安全的Flash写入 */
#include "ota_flash_write.h"
/* 双缓冲写入:确保任何时刻至少有一个完整副本 */
#define WRITE_BUFFER_SIZE 256
typedef struct {
uint8_t buffer[WRITE_BUFFER_SIZE];
uint16_t len;
uint32_t target_addr;
bool pending;
} WriteBuffer_t;
static WriteBuffer_t s_write_buf = {0};
/* 缓冲写入(累积到一页再写入) */
ErrorCode_t OTA_FlashWriteBuffered(uint32_t addr, const uint8_t* data, uint16_t len) {
while (len > 0) {
uint16_t space = WRITE_BUFFER_SIZE - s_write_buf.len;
uint16_t to_copy = (len < space) ? len : space;
memcpy(s_write_buf.buffer + s_write_buf.len, data, to_copy);
s_write_buf.len += to_copy;
data += to_copy;
len -= to_copy;
/* 缓冲区满,执行写入 */
if (s_write_buf.len >= WRITE_BUFFER_SIZE) {
ErrorCode_t err = OTA_FlashWritePage(s_write_buf.target_addr,
s_write_buf.buffer,
WRITE_BUFFER_SIZE);
if (err != ERR_OK) {
return err;
}
s_write_buf.target_addr += WRITE_BUFFER_SIZE;
s_write_buf.len = 0;
}
}
return ERR_OK;
}
/* 刷新剩余数据 */
ErrorCode_t OTA_FlashWriteFlush(void) {
if (s_write_buf.len > 0) {
/* 补齐到页大小(用0xFF填充,不影响后续覆盖) */
memset(s_write_buf.buffer + s_write_buf.len, 0xFF,
WRITE_BUFFER_SIZE - s_write_buf.len);
ErrorCode_t err = OTA_FlashWritePage(s_write_buf.target_addr,
s_write_buf.buffer,
WRITE_BUFFER_SIZE);
if (err != ERR_OK) {
return err;
}
s_write_buf.len = 0;
}
return ERR_OK;
}
/* 安全的页写入(擦除+写入+验证) */
ErrorCode_t OTA_FlashWritePage(uint32_t addr, const uint8_t* data, uint16_t len) {
/* 1. 检查地址对齐 */
if (addr % 256 != 0 || len != 256) {
return ERR_INVALID_PARAM;
}
/* 2. 检查是否需要擦除扇区 */
uint32_t sector_start = addr & ~(FLASH_SECTOR_SIZE - 1);
static uint32_t s_last_erased_sector = 0xFFFFFFFF;
if (sector_start != s_last_erased_sector) {
HAL_FLASH_Unlock();
FLASH_EraseInitTypeDef erase_init = {
.TypeErase = FLASH_TYPEERASE_SECTORS,
.Sector = GetSectorNumber(sector_start),
.NbSectors = 1,
.VoltageRange = FLASH_VOLTAGE_RANGE_3
};
uint32_t sector_error = 0;
HAL_StatusTypeDef status = HAL_FLASHEx_Erase(&erase_init, §or_error);
if (status != HAL_OK) {
HAL_FLASH_Lock();
LOG_ERROR("OTA", "Sector erase failed at 0x%08X", sector_start);
return ERR_FLASH_ERASE_FAIL;
}
s_last_erased_sector = sector_start;
}
/* 3. 写入数据 */
for (uint16_t i = 0; i < len; i += 4) {
uint32_t word = *((uint32_t*)(data + i));
HAL_StatusTypeDef status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD,
addr + i, word);
if (status != HAL_OK) {
HAL_FLASH_Lock();
LOG_ERROR("OTA", "Flash program failed at 0x%08X", addr + i);
return ERR_FLASH_WRITE_FAIL;
}
}
/* 4. 回读验证 */
for (uint16_t i = 0; i < len; i += 4) {
uint32_t written = *((volatile uint32_t*)(addr + i));
uint32_t expected = *((uint32_t*)(data + i));
if (written != expected) {
HAL_FLASH_Lock();
LOG_ERROR("OTA", "Verify failed at 0x%08X: expected 0x%08X, got 0x%08X",
addr + i, expected, written);
return ERR_FLASH_VERIFY_FAIL;
}
}
HAL_FLASH_Lock();
return ERR_OK;
}
五、签名验证与安全启动

5.1 固件签名格式
/* firmware_signature.h - 固件签名格式 */
#ifndef FIRMWARE_SIGNATURE_H
#define FIRMWARE_SIGNATURE_H
#include <stdint.h>
/* 签名块位于固件末尾,共256字节 */
#define SIGNATURE_BLOCK_SIZE 256
#define SIGNATURE_MAGIC 0x5349474E /* "SIGN" */
/* 签名算法枚举 */
typedef enum {
SIG_ALG_RSA_PSS_SHA256 = 0,
SIG_ALG_ECDSA_P256_SHA256 = 1,
SIG_ALG_ED25519 = 2,
} SignatureAlgorithm_t;
/* 固件头部(位于固件起始) */
typedef struct __attribute__((packed)) {
uint32_t magic; /* "FIRM" */
uint32_t header_version; /* 头部格式版本 */
uint32_t firmware_version; /* 固件版本号 */
uint32_t firmware_size; /* 固件大小(不含签名块) */
uint32_t target_hardware; /* 目标硬件ID */
uint32_t build_timestamp; /* 构建时间戳 */
uint8_t git_commit[20]; /* Git commit SHA */
uint32_t crc32; /* 固件CRC32 */
uint8_t reserved[28]; /* 保留 */
} FirmwareHeader_t;
/* 签名块(位于固件末尾) */
typedef struct __attribute__((packed)) {
uint32_t magic; /* "SIGN" */
uint16_t algorithm; /* 签名算法 */
uint16_t key_version; /* 公钥版本(支持密钥轮换) */
uint8_t signature[64]; /* 签名数据 */
uint8_t public_key_hash[32]; /* 公钥哈希(验证用) */
uint8_t reserved[152]; /* 保留 */
} SignatureBlock_t;
/* 验证结果 */
typedef enum {
VERIFY_OK = 0,
VERIFY_ERR_MAGIC,
VERIFY_ERR_HASH,
VERIFY_ERR_SIGNATURE,
VERIFY_ERR_VERSION,
VERIFY_ERR_HARDWARE,
VERIFY_ERR_ROLLBACK,
} VerifyResult_t;
#endif /* FIRMWARE_SIGNATURE_H */
5.2 Bootloader中的签名验证
/* bootloader_verify.c - Bootloader签名验证 */
#include "bootloader_verify.h"
#include "firmware_signature.h"
#include "flash_layout.h"
/* 嵌入式公钥(产线烧录,只读) */
static const uint8_t s_embedded_public_key[64] = {
/* 从ota_signing_pubkey.pem转换的原始字节 */
#include "public_key.inc"
};
/* 版本防回滚:存储于备份区的最小允许版本 */
#define MIN_ALLOWED_VERSION_ADDR (BACKUP_DATA_START + 0x100)
/* 验证固件完整性 */
VerifyResult_t Bootloader_VerifyFirmware(uint32_t partition_start) {
/* 1. 读取固件头部 */
const FirmwareHeader_t* header = (const FirmwareHeader_t*)partition_start;
if (header->magic != 0x4649524D) { /* "FIRM" */
LOG_ERROR("BOOT", "Invalid firmware magic: 0x%08X", header->magic);
return VERIFY_ERR_MAGIC;
}
/* 2. 硬件ID匹配 */
uint32_t current_hw_id = HAL_GetHardwareID();
if (header->target_hardware != current_hw_id) {
LOG_ERROR("BOOT", "Hardware mismatch: fw=0x%08X, hw=0x%08X",
header->target_hardware, current_hw_id);
return VERIFY_ERR_HARDWARE;
}
/* 3. 版本防回滚检查 */
uint32_t min_version = *(volatile uint32_t*)MIN_ALLOWED_VERSION_ADDR;
if (header->firmware_version < min_version) {
LOG_ERROR("BOOT", "Rollback attempt: fw=%lu, min=%lu",
header->firmware_version, min_version);
return VERIFY_ERR_ROLLBACK;
}
/* 4. CRC32校验 */
uint32_t calc_crc = CRC32_Calculate(
(const uint8_t*)partition_start,
header->firmware_size
);
if (calc_crc != header->crc32) {
LOG_ERROR("BOOT", "CRC mismatch: calc=0x%08X, stored=0x%08X",
calc_crc, header->crc32);
return VERIFY_ERR_HASH;
}
/* 5. 读取签名块 */
const SignatureBlock_t* sig = (const SignatureBlock_t*)
(partition_start + header->firmware_size);
if (sig->magic != SIGNATURE_MAGIC) {
LOG_ERROR("BOOT", "Invalid signature magic");
return VERIFY_ERR_MAGIC;
}
/* 6. 公钥哈希验证(防止公钥被替换) */
uint8_t key_hash[32];
SHA256_Calculate(s_embedded_public_key, sizeof(s_embedded_public_key), key_hash);
if (memcmp(key_hash, sig->public_key_hash, 32) != 0) {
LOG_ERROR("BOOT", "Public key hash mismatch!");
return VERIFY_ERR_SIGNATURE;
}
/* 7. 签名验证 */
bool sig_valid = false;
switch (sig->algorithm) {
case SIG_ALG_ECDSA_P256_SHA256:
sig_valid = ECDSA_Verify_P256(
s_embedded_public_key,
(const uint8_t*)partition_start, /* 签名覆盖整个固件 */
header->firmware_size,
sig->signature
);
break;
case SIG_ALG_RSA_PSS_SHA256:
sig_valid = RSA_Verify_PSS(
s_embedded_public_key,
(const uint8_t*)partition_start,
header->firmware_size,
sig->signature
);
break;
default:
LOG_ERROR("BOOT", "Unsupported signature algorithm: %d", sig->algorithm);
return VERIFY_ERR_SIGNATURE;
}
if (!sig_valid) {
LOG_ERROR("BOOT", "Signature verification failed");
return VERIFY_ERR_SIGNATURE;
}
LOG_INFO("BOOT", "Firmware verification passed");
LOG_INFO("BOOT", " Version: %lu", header->firmware_version);
LOG_INFO("BOOT", " Size: %lu", header->firmware_size);
LOG_INFO("BOOT", " Build: %02X%02X...%02X%02X",
header->git_commit[0], header->git_commit[1],
header->git_commit[18], header->git_commit[19]);
return VERIFY_OK;
}
5.3 密钥管理与轮换
/* key_management.c - 密钥管理 */
/* 支持多版本公钥并存(密钥轮换过渡期) */
#define MAX_KEY_VERSIONS 3
typedef struct {
uint16_t version;
uint8_t public_key[64];
bool is_valid;
} KeySlot_t;
static KeySlot_t s_key_slots[MAX_KEY_VERSIONS] = {0};
/* 初始化密钥槽(从OTP/EFuse读取) */
void KeyManager_Init(void) {
/* 从OTP读取主密钥 */
OTP_ReadKey(0, s_key_slots[0].public_key, 64);
s_key_slots[0].version = OTP_ReadKeyVersion(0);
s_key_slots[0].is_valid = true;
/* 读取备用密钥(用于轮换) */
for (int i = 1; i < MAX_KEY_VERSIONS; i++) {
if (OTP_HasKey(i)) {
OTP_ReadKey(i, s_key_slots[i].public_key, 64);
s_key_slots[i].version = OTP_ReadKeyVersion(i);
s_key_slots[i].is_valid = true;
}
}
}
/* 查找匹配的公钥 */
const uint8_t* KeyManager_FindKey(uint16_t version) {
for (int i = 0; i < MAX_KEY_VERSIONS; i++) {
if (s_key_slots[i].is_valid && s_key_slots[i].version == version) {
return s_key_slots[i].public_key;
}
}
return NULL;
}
/* 更新最小允许版本(防回滚) */
void KeyManager_UpdateMinVersion(uint32_t version) {
/* 原子写入备份区 */
HAL_FLASH_Unlock();
HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, MIN_ALLOWED_VERSION_ADDR, version);
HAL_FLASH_Lock();
LOG_INFO("KEY", "Minimum allowed version updated to %lu", version);
}
六、双分区启动与回滚机制

6.1 启动标志位设计
/* boot_info.h - 启动信息结构 */
#ifndef BOOT_INFO_H
#define BOOT_INFO_H
#include <stdint.h>
#include <stdbool.h>
#define BOOT_INFO_MAGIC 0x424F4F54 /* "BOOT" */
#define BOOT_INFO_VERSION 2
/* 分区状态 */
typedef enum {
PART_STATUS_EMPTY = 0, /* 分区为空 */
PART_STATUS_VALID = 1, /* 固件有效但未测试 */
PART_STATUS_ACTIVE = 2, /* 当前运行固件 */
PART_STATUS_ROLLBACK = 3, /* 标记回滚 */
} PartitionStatus_t;
/* 启动信息(存储于Partition Info区) */
typedef struct __attribute__((packed)) {
uint32_t magic; /* \"BOOT\" */
uint16_t version; /* 格式版本 */
/* 分区A信息 */
uint8_t a_status; /* PartitionStatus_t */
uint32_t a_version; /* 固件版本 */
uint32_t a_size; /* 固件大小 */
uint32_t a_crc32; /* CRC校验 */
uint8_t a_boot_attempts; /* 启动尝试次数 */
/* 分区B信息 */
uint8_t b_status;
uint32_t b_version;
uint32_t b_size;
uint32_t b_crc32;
uint8_t b_boot_attempts;
/* 全局状态 */
uint8_t active_partition; /* 0=A, 1=B */
uint8_t rollback_count; /* 回滚次数 */
uint32_t total_boot_count; /* 总启动次数 */
uint32_t last_boot_time; /* 上次启动时间 */
uint8_t reserved[20]; /* 保留扩展 */
uint32_t crc32; /* 本记录CRC */
} BootInfo_t;
/* 启动决策结果 */
typedef enum {
BOOT_DECISION_A = 0, /* 启动分区A */
BOOT_DECISION_B, /* 启动分区B */
BOOT_DECISION_RECOVERY, /* 进入恢复模式 */
} BootDecision_t;
#endif /* BOOT_INFO_H */
6.2 Bootloader启动决策逻辑
/* bootloader_main.c - Bootloader主逻辑 */
#include "bootloader_main.h"
#include "boot_info.h"
#include "bootloader_verify.h"
/* 启动尝试阈值:超过则视为失败 */
#define BOOT_ATTEMPT_THRESHOLD 3
/* 启动成功确认时间:运行30秒后视为成功 */
#define BOOT_SUCCESS_TIME_MS 30000
int main(void) {
/* 初始化硬件 */
HAL_Init();
SystemClock_Config();
LOG_INFO(\"BOOT\", \"Bootloader starting...\");
/* 1. 读取启动信息 */
BootInfo_t boot_info;
if (!BootInfo_Read(&boot_info)) {
LOG_ERROR(\"BOOT\", \"Failed to read boot info, using defaults\");
BootInfo_InitDefaults(&boot_info);
}
/* 2. 检查是否有OTA完成标记(App写入) */
if (BootInfo_HasOtaCompleteMark()) {
LOG_INFO(\"BOOT\", \"OTA complete mark detected\");
BootInfo_ClearOtaMark();
/* 新固件首次启动,增加尝试计数 */
if (boot_info.active_partition == 0) {
boot_info.a_boot_attempts++;
} else {
boot_info.b_boot_attempts++;
}
BootInfo_Write(&boot_info);
}
/* 3. 启动决策 */
BootDecision_t decision = Bootloader_Decide(&boot_info);
switch (decision) {
case BOOT_DECISION_A:
LOG_INFO(\"BOOT\", \"Starting partition A (v%lu)\", boot_info.a_version);
if (Bootloader_VerifyFirmware(APP_A_START) == VERIFY_OK) {
Bootloader_JumpToApp(APP_A_START);
} else {
LOG_ERROR(\"BOOT\", \"Partition A verify failed, trying B\");
decision = BOOT_DECISION_B;
}
break;
case BOOT_DECISION_B:
LOG_INFO(\"BOOT\", \"Starting partition B (v%lu)\", boot_info.b_version);
if (Bootloader_VerifyFirmware(APP_B_START) == VERIFY_OK) {
Bootloader_JumpToApp(APP_B_START);
} else {
LOG_ERROR(\"BOOT\", \"Partition B verify failed\");
decision = BOOT_DECISION_RECOVERY;
}
break;
case BOOT_DECISION_RECOVERY:
default:
LOG_FATAL(\"BOOT\", \"No valid firmware, entering recovery\");
Bootloader_EnterRecoveryMode();
break;
}
/* 不会执行到这里 */\n while(1);\n}
/* 启动决策核心算法 */
BootDecision_t Bootloader_Decide(const BootInfo_t* info) {
uint8_t active = info->active_partition;
uint8_t inactive = (active == 0) ? 1 : 0;
/* 情况1: 新固件首次启动,检查尝试次数 */
if (active == 0 && info->a_status == PART_STATUS_VALID) {
if (info->a_boot_attempts >= BOOT_ATTEMPT_THRESHOLD) {
LOG_WARN(\"BOOT\", \"Partition A failed %d times, rolling back\",
info->a_boot_attempts);
return BOOT_DECISION_B; /* 回滚到B */
}
} else if (active == 1 && info->b_status == PART_STATUS_VALID) {
if (info->b_boot_attempts >= BOOT_ATTEMPT_THRESHOLD) {
LOG_WARN(\"BOOT\", \"Partition B failed %d times, rolling back\",
info->b_boot_attempts);
return BOOT_DECISION_A;
}
}
/* 情况2: 当前活动分区有效,直接启动 */
if (active == 0 && info->a_status == PART_STATUS_ACTIVE) {
return BOOT_DECISION_A;
} else if (active == 1 && info->b_status == PART_STATUS_ACTIVE) {
return BOOT_DECISION_B;
}
/* 情况3: 活动分区无效,尝试另一分区 */
if (active == 0 && info->b_status == PART_STATUS_ACTIVE) {
LOG_WARN(\"BOOT\", \"Partition A invalid, falling back to B\");
return BOOT_DECISION_B;
} else if (active == 1 && info->a_status == PART_STATUS_ACTIVE) {
LOG_WARN(\"BOOT\", \"Partition B invalid, falling back to A\");
return BOOT_DECISION_A;
}
/* 情况4: 所有分区无效 */
LOG_FATAL(\"BOOT\", \"No valid partition available\");
return BOOT_DECISION_RECOVERY;
}
/* 跳转到App */
void Bootloader_JumpToApp(uint32_t app_addr) {
/* 1. 获取App的复位向量 */
uint32_t app_stack_ptr = *(volatile uint32_t*)app_addr;
uint32_t app_reset_vec = *(volatile uint32_t*)(app_addr + 4);
/* 2. 验证向量表合法性 */
if ((app_stack_ptr & 0x2FFE0000) != 0x20000000) {
LOG_FATAL(\"BOOT\", \"Invalid stack pointer: 0x%08X\", app_stack_ptr);
return;
}
/* 3. 关闭中断 */
__disable_irq();
/* 4. 重置外设 */
HAL_DeInit();
/* 5. 设置向量表偏移 */
SCB->VTOR = app_addr;
/* 6. 设置主堆栈指针 */
__set_MSP(app_stack_ptr);
/* 7. 跳转到App */
typedef void (*AppEntry_t)(void);
AppEntry_t app_entry = (AppEntry_t)app_reset_vec;
app_entry();
/* 不会返回 */
}
6.3 App中的启动成功确认
/* app_main.c - App启动成功确认 */
#include \"app_main.h\"
#include \"boot_info.h\"
/* 启动成功确认定时器 */
static uint32_t s_boot_confirm_timer = 0;
void App_Init(void) {
/* 初始化所有模块 */
HAL_Init();
SystemClock_Config();
Peripherals_Init();
/* 启动30秒倒计时,确认启动成功 */
s_boot_confirm_timer = HAL_GetTick();
LOG_INFO(\"APP\", \"Application started, waiting for boot confirmation...\");
}
void App_MainLoop(void) {
/* 主循环 */
while (1) {
/* 处理业务逻辑 */
ProcessTasks();
/* 检查是否需要确认启动成功 */
if (s_boot_confirm_timer > 0 &&
(HAL_GetTick() - s_boot_confirm_timer) > BOOT_SUCCESS_TIME_MS) {
/* 30秒无异常,确认启动成功 */
BootInfo_ConfirmBootSuccess();
s_boot_confirm_timer = 0;
LOG_INFO(\"APP\", \"Boot confirmed successful\");
}
/* 喂看门狗 */
IWDG_Refresh();
}
}
/* 确认启动成功:将分区状态从VALID升级为ACTIVE */
void BootInfo_ConfirmBootSuccess(void) {
BootInfo_t info;
if (!BootInfo_Read(&info)) return;
if (info.active_partition == 0) {
info.a_status = PART_STATUS_ACTIVE;
info.a_boot_attempts = 0; /* 重置尝试计数 */
} else {
info.b_status = PART_STATUS_ACTIVE;
info.b_boot_attempts = 0;
}
/* 更新防回滚最小版本 */
uint32_t current_version = (info.active_partition == 0) ?
info.a_version : info.b_version;
KeyManager_UpdateMinVersion(current_version);
BootInfo_Write(&info);
}
七、OTA升级完整流程
/* ota_main.c - OTA升级主流程 */
ErrorCode_t OTA_StartUpgrade(const char* version_url) {
OtaProgressRecord_t progress;
/* 1. 检查当前状态 */
if (OTA_HasPendingUpdate()) {
LOG_INFO(\"OTA\", \"Resuming previous update\");
return OTA_ResumeUpdate();
}
/* 2. 查询服务器 */
OtaVersionInfo_t version_info;
ErrorCode_t err = OTA_QueryVersion(version_url, &version_info);
if (err != ERR_OK) return err;
/* 3. 版本比较 */
uint32_t current_version = APP_GetCurrentVersion();
if (version_info.version <= current_version) {
LOG_INFO(\"OTA\", \"No update needed: current=%lu, remote=%lu\",
current_version, version_info.version);
return ERR_OK;
}
/* 4. 检查空间 */
if (version_info.full_size > APP_A_SIZE) {
LOG_ERROR(\"OTA\", \"Firmware too large: %lu > %lu\",
version_info.full_size, APP_A_SIZE);
return ERR_OTA_NO_SPACE;
}
/* 5. 确定目标分区 */
uint8_t target_partition = (OTA_GetActivePartition() == 0) ? 1 : 0;
LOG_INFO(\"OTA\", \"Target partition: %c\", (target_partition == 0) ? 'A' : 'B');
/* 6. 初始化进度记录 */
memset(&progress, 0, sizeof(progress));
progress.magic = OTA_PROGRESS_MAGIC;
progress.version = OTA_PROGRESS_VERSION;
progress.target_version = version_info.version;
progress.total_size = version_info.diff_size;
progress.state = OTA_STATE_DOWNLOADING;
progress.target_partition = target_partition;
progress.chunk_size = 1024; /* 1KB分块 */
OTA_ProgressUpdate(&progress);
/* 7. 下载差分包 */
err = OTA_DownloadDiffPackage(&version_info, &progress);
if (err != ERR_OK) {
OTA_HandleFailure(err, &progress);
return err;
}
/* 8. 应用差分补丁 */
progress.state = OTA_STATE_PATCHING;
OTA_ProgressUpdate(&progress);
err = OTA_ApplyDiffPatch(/* ... */);
if (err != ERR_OK) {
OTA_HandleFailure(err, &progress);
return err;
}
/* 9. 验证新固件 */
progress.state = OTA_STATE_VERIFYING;
OTA_ProgressUpdate(&progress);
uint32_t partition_addr = (target_partition == 0) ? APP_A_START : APP_B_START;
VerifyResult_t verify = Bootloader_VerifyFirmware(partition_addr);
if (verify != VERIFY_OK) {
LOG_ERROR(\"OTA\", \"Verification failed: %d\", verify);
OTA_ClearPartition(target_partition);
OTA_HandleFailure(ERR_OTA_VERIFY_FAIL, &progress);
return ERR_OTA_VERIFY_FAIL;
}
/* 10. 提交更新 */
progress.state = OTA_STATE_COMMITTING;
OTA_ProgressUpdate(&progress);
err = OTA_CommitUpdate(target_partition, version_info.version);
if (err != ERR_OK) {
OTA_HandleFailure(err, &progress);
return err;
}
/* 11. 完成 */
progress.state = OTA_STATE_COMMITTED;
OTA_ProgressUpdate(&progress);
OTA_ProgressClear();
LOG_INFO(\"OTA\", \"Upgrade completed successfully\");
LOG_INFO(\"OTA\", \"Rebooting to activate new firmware...\");
HAL_Delay(1000);
NVIC_SystemReset();
return ERR_OK; /* 不会执行到这里 */
}
/* 提交更新:原子切换启动分区 */
ErrorCode_t OTA_CommitUpdate(uint8_t new_partition, uint32_t new_version) {
BootInfo_t info;
if (!BootInfo_Read(&info)) {
return ERR_OTA_BOOT_INFO_FAIL;
}
/* 原子更新:先标记新分区为VALID,再切换active_partition */
if (new_partition == 0) {
info.a_status = PART_STATUS_VALID;
info.a_version = new_version;
info.a_boot_attempts = 0;
} else {
info.b_status = PART_STATUS_VALID;\n info.b_version = new_version;\n info.b_boot_attempts = 0;
}
/* 关键:先写状态,再切换active */
if (!BootInfo_Write(&info)) {
return ERR_OTA_BOOT_INFO_FAIL;
}
/* 切换活动分区 */
info.active_partition = new_partition;
if (!BootInfo_Write(&info)) {
/* 尝试回滚 */
return ERR_OTA_COMMIT_FAIL;
}
return ERR_OK;
}
八、鸿蒙生态(OpenHarmony)OTA适配
在OpenHarmony的轻内核(LiteOS-M)中,OTA需要适配HDF框架和分布式能力:
/* openharmony_ota_adapter.c */
#include \"hdf_device_desc.h\"
#include \"hdf_log.h\"
#include \"ota_main.h\"
/* 注册为HDF设备 */
static int32_t OtaDriverDispatch(struct HdfDeviceIoClient* client, int cmd,
struct HdfSBuf* data, struct HdfSBuf* reply) {
switch (cmd) {
case OTA_CMD_CHECK_UPDATE:
return OTA_HDF_CheckUpdate(reply);
case OTA_CMD_START_DOWNLOAD:
return OTA_HDF_StartDownload(data, reply);
case OTA_CMD_GET_PROGRESS:
return OTA_HDF_GetProgress(reply);
case OTA_CMD_VERIFY_FIRMWARE:
return OTA_HDF_VerifyFirmware(data, reply);
case OTA_CMD_COMMIT_UPDATE:
return OTA_HDF_CommitUpdate(data, reply);
default:
return HDF_ERR_NOT_SUPPORT;
}
}
/* 分布式OTA:通过软总线接收其他设备的升级包 */
void OTA_DistributedReceive(const char* source_device, const uint8_t* data, uint32_t len) {
LOG_INFO(\"OTA\", \"Received distributed OTA package from %s, size=%lu\",
source_device, len);
/* 验证来源设备身份 */
if (!Distributed_VerifyDevice(source_device)) {
LOG_ERROR(\"OTA\", \"Device verification failed\");
return;
}
/* 保存到本地并启动升级 */
OTA_SaveDistributedPackage(data, len);
OTA_StartUpgradeFromLocal();
}
九、总结与最佳实践清单
| 实践项 | 核心原则 | 关键实现 |
|---|---|---|
| 双分区 | 始终保留可启动的旧固件 | A/B分区各占50% Flash |
| 差分升级 | 节省流量和时间 | HDiffPatch,RAM<64KB可用 |
| 断电保护 | 任何时刻可恢复 | 双缓冲进度记录,原子状态更新 |
| 签名验证 | 防止恶意固件 | ECDSA P-256,公钥烧录OTP |
| 版本防回滚 | 防止降级攻击 | 最小允许版本持久化存储 |
| 自动回滚 | 新固件失败自愈 | 启动尝试计数,3次失败回退 |
| 原子提交 | 升级不可中断 | 先标记VALID,再切换ACTIVE |
OTA系统的最高设计原则是:任何单点故障都不能导致设备变砖。 通过双分区的物理冗余、进度记录的双缓冲原子写入、启动决策的智能回滚,我们构建了一个即使在最恶劣条件下也能保持可启动性的升级系统。
转载自:https://blog.csdn.net/u014727709/article/details/162602724
欢迎 👍点赞✍评论⭐收藏,欢迎指正
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐
所有评论(0)