在这里插入图片描述

每日一句正能量

成熟的情绪管理,是允许情绪自然存在,任它穿过身体。
成熟不是压抑或控制情绪,而是不再与情绪对抗。像对待天气一样,允许愤怒、悲伤、恐惧来临,感受它们在身体里的流动,然后看着它们离开。这种“不粘着”的态度,才是真正的情绪自由。

一、前言:为什么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, &sector_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, &sector_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
欢迎 👍点赞✍评论⭐收藏,欢迎指正

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐