add ota algorithm for device

1. effective "Differential Upgrade" patch algorithm with high compression rate
2. effective recovery algorithm support recovery firmware in blocks which has low memory consumption and wear-leveling strategies, especially suitable for embeded devices with low RAM.
3. add sample ota bootloader project, see:
board\TencentOS_tiny_EVB_MX_Plus\KEIL\ota\ota_bootloader_recovery
4. add sample application project for download firmware through http, see:
board\TencentOS_tiny_EVB_MX_Plus\KEIL\ota\ota_application_download_through_http
5. add sample application project for download firmware through qcloud explorer console, see:
board\TencentOS_tiny_EVB_MX_Plus\KEIL\ota\ota_application_download_through_qcloud_iot_explorer
6. an OTA markdown document is pending
This commit is contained in:
daishengdong
2020-06-02 15:03:42 +08:00
parent 84faf16765
commit 5b51d50ade
177 changed files with 42367 additions and 1233 deletions

View File

@@ -0,0 +1,88 @@
/*----------------------------------------------------------------------------
* Tencent is pleased to support the open source community by making TencentOS
* available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
* If you have downloaded a copy of the TencentOS binary from Tencent, please
* note that the TencentOS binary is licensed under the BSD 3-Clause License.
*
* If you have downloaded a copy of the TencentOS source code from Tencent,
* please note that TencentOS source code is licensed under the BSD 3-Clause
* License, except for the third-party components listed below which are
* subject to different license terms. Your integration of TencentOS into your
* own projects may require compliance with the BSD 3-Clause License, as well
* as the other licenses applicable to the third-party components included
* within TencentOS.
*---------------------------------------------------------------------------*/
#ifndef _OTA_PATCH_H_
#define _OTA_PATCH_H_
#include "stddef.h"
#include "stdint.h"
#define ERROR() \
rc = -1; \
goto OUT;
#define FREE(p) if (p) { free(p); }
#define CMD_COPY 0
#define CMD_DIFF 1
#define CMD_EXTRA 2
#define BLK_UPPER_BOUND(off, blk_len) (ALIGN_UP((off) + 1, (blk_len)))
#define BLK_LOWER_BOUND(idx, blk_len) ((idx) * (blk_len))
#define FOLD_N(x, n) ((n) * (x))
#define THE_BUF(buf, idx, blk_len) ((buf) + (idx) * (blk_len))
#define BLK_IDX(off, blk_len) ((off) / (blk_len))
#define ALIGN_UP(v, align) (((v) + ((align) - 1)) & ~((align) - 1))
#define BLK_CNT(size, blk_len) (((size) + (blk_len) - 1) / (blk_len))
#pragma pack(push, 1)
typedef struct patch_header_st {
uint16_t blk_len;
uint16_t blk_cnt;
} patch_hdr_t;
typedef struct patch_for_block_header_st {
uint16_t unzipped_len;
uint16_t zipped_len;
} patch4blk_hdr_t;
typedef struct patch_for_block_info_st {
uint16_t blk_idx;
uint16_t cmd_cnt;
uint16_t ctrl_size;
uint16_t diff_size;
} patch4blk_info_t;
#pragma pack(pop)
typedef struct backup_map_st {
uint16_t *cache;
uint16_t backup_n;
uint16_t cursor;
uint16_t blk_len;
uint32_t start;
} bkup_map_t;
typedef enum query_res_en {
QUERY_RESULT_OK,
QUERY_RESULT_NOT_EXIST,
QUERY_RESULT_FETCH_FAILED,
} query_res_t;
int ota_patch(uint32_t patch, size_t patchsize, size_t ota_size);
int ota_patch_xip(uint8_t *patch, size_t patchsize, size_t ota_size);
#endif

View File

@@ -0,0 +1,32 @@
/*----------------------------------------------------------------------------
* Tencent is pleased to support the open source community by making TencentOS
* available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
* If you have downloaded a copy of the TencentOS binary from Tencent, please
* note that the TencentOS binary is licensed under the BSD 3-Clause License.
*
* If you have downloaded a copy of the TencentOS source code from Tencent,
* please note that TencentOS source code is licensed under the BSD 3-Clause
* License, except for the third-party components listed below which are
* subject to different license terms. Your integration of TencentOS into your
* own projects may require compliance with the BSD 3-Clause License, as well
* as the other licenses applicable to the third-party components included
* within TencentOS.
*---------------------------------------------------------------------------*/
#ifndef _OTA_RECOVERY_H_
#define _OTA_RECOVERY_H_
#include "ota_env.h"
#include "ota_info.h"
#include "ota_flash.h"
#include "ota_image.h"
#include "ota_patch.h"
int ota_recovery(void);
int ota_recovery_xip(void);
#endif /* _OTA_RECOVERY_H_ */

View File

@@ -0,0 +1,370 @@
/*----------------------------------------------------------------------------
* Tencent is pleased to support the open source community by making TencentOS
* available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
* If you have downloaded a copy of the TencentOS binary from Tencent, please
* note that the TencentOS binary is licensed under the BSD 3-Clause License.
*
* If you have downloaded a copy of the TencentOS source code from Tencent,
* please note that TencentOS source code is licensed under the BSD 3-Clause
* License, except for the third-party components listed below which are
* subject to different license terms. Your integration of TencentOS into your
* own projects may require compliance with the BSD 3-Clause License, as well
* as the other licenses applicable to the third-party components included
* within TencentOS.
*---------------------------------------------------------------------------*/
#include "ota_patch.h"
#include "ota_flash.h"
#include "ota_partition.h"
#include "lzma_uncompress.h"
static uint16_t offtin_u16(uint8_t *buf)
{
int32_t y;
y = buf[1];
y = y * 256; y += buf[0];
return y;
}
static int backup_map_create(bkup_map_t *bkup_map, size_t ota_size, uint16_t blk_len)
{
uint16_t i = 0;
uint16_t *cache;
uint16_t remain_blk_cnt;
uint32_t start;
size_t remain_size;
if (ota_partition_size(OTA_PARTITION_OTA) <= ALIGN_UP(ota_size, blk_len)) {
return -1;
}
remain_size = ota_partition_size(OTA_PARTITION_OTA) - ALIGN_UP(ota_size, blk_len);
remain_blk_cnt = BLK_CNT(remain_size, blk_len);
start = ota_partition_start(OTA_PARTITION_OTA) + ALIGN_UP(ota_size, blk_len);
cache = malloc(remain_blk_cnt * sizeof(uint16_t));
if (cache == NULL) {
return -1;
}
for (i = 0; i < remain_blk_cnt; ++i) {
cache[i] = (uint16_t)-1;
}
bkup_map->cache = cache;
bkup_map->backup_n = remain_blk_cnt;
bkup_map->blk_len = blk_len;
bkup_map->start = start;
bkup_map->cursor =0;
return 0;
}
static int backup_map_destroy(bkup_map_t *bkup_map)
{
free(bkup_map->cache);
return 0;
}
static int backup_map_add(bkup_map_t *bkup_map, uint16_t blk_idx, uint32_t backup_ed_addr, uint8_t *blk_buf)
{
uint16_t slot = bkup_map->cursor;
uint16_t blk_len = bkup_map->blk_len;
uint32_t backup_ee_addr = THE_BUF(bkup_map->start, slot, bkup_map->blk_len);
if (ota_flash_erase(backup_ee_addr, blk_len) != 0) {
return -1;
}
if (ota_flash_read(backup_ed_addr, blk_buf, blk_len) != 0) {
return -1;
}
if (ota_flash_write(backup_ee_addr, blk_buf, blk_len) != 0) {
return -1;
}
bkup_map->cache[slot] = blk_idx;
bkup_map->cursor = (slot + 1) % bkup_map->backup_n;
return 0;
}
static query_res_t backup_map_query(bkup_map_t *bkup_map, uint16_t blk_idx, uint8_t *blk_buf)
{
uint16_t i = 0;
uint32_t backup_ee_addr;
uint16_t blk_len = bkup_map->blk_len;
for (i = 0; i < bkup_map->backup_n; ++i) {
if (bkup_map->cache[i] == blk_idx) {
backup_ee_addr = THE_BUF(bkup_map->start, i, blk_len);
if (ota_flash_read(backup_ee_addr, blk_buf, blk_len) != 0) {
return QUERY_RESULT_FETCH_FAILED;
}
return QUERY_RESULT_OK;
}
}
return QUERY_RESULT_NOT_EXIST;
}
int ota_patch(uint32_t patch, size_t patchsize, size_t ota_size)
{
int rc = 0, i = 0;
/* the patch information stuff */
uint8_t *block = NULL, *blk_buf = NULL;
uint8_t *unzipped_patch = NULL, *zipped_patch = NULL;
uint16_t blk_len, blk_cnt;
uint16_t unzipped_len, zipped_len;
size_t the_unzipped_len, the_zipped_len;
/* the backup stuff */
bkup_map_t bkup_map;
query_res_t res;
/* the patch4blk stuff */
uint8_t X;
uint16_t I, N, Y, Z, C, D;
uint8_t *ctrl_blk, *diff_blk, *extra_blk;
uint16_t cursor = 0;
uint16_t old_idx, old_offset;
patch_hdr_t patch_hdr;
patch4blk_hdr_t patch4blk_hdr;
patch4blk_info_t *patch4blk_info;
/*
format of patch:
patch_hdr + (patch4blk_hdr + zipped(patch4blk)) * N
patch_hdr:
0 2 length of one block
4 2 total count of blocks in the patch
patch4blk_hdr:
4 2 original length of the patch
8 2 zipped length of the patch
*/
/* read the patch header */
if (ota_flash_read(patch, &patch_hdr, sizeof(patch_hdr_t)) != 0) {
ERROR();
}
patch += sizeof(patch_hdr_t);
patchsize -= sizeof(patch_hdr_t);
if (patchsize <= 0) {
ERROR();
}
blk_len = patch_hdr.blk_len;
blk_cnt = patch_hdr.blk_cnt;
/* create backup map to cache old blocks */
if (!ota_partition_is_pingpong() &&
backup_map_create(&bkup_map, ota_size, blk_len) != 0) {
ERROR();
}
block = malloc(blk_len);
if (!block) {
ERROR();
}
blk_buf = malloc(blk_len);
if (!blk_buf) {
ERROR();
}
while (blk_cnt--) {
/* read the patch4blk header */
if (ota_flash_read(patch, &patch4blk_hdr, sizeof(patch4blk_hdr_t)) != 0) {
ERROR();
}
patch += sizeof(patch4blk_hdr_t);
patchsize -= sizeof(patch4blk_hdr_t);
if (patchsize <= 0) {
ERROR();
}
unzipped_len = patch4blk_hdr.unzipped_len;
zipped_len = patch4blk_hdr.zipped_len;
the_unzipped_len = unzipped_len;
the_zipped_len = zipped_len;
/* some malloc */
zipped_patch = malloc(the_zipped_len);
if (!zipped_patch) {
ERROR();
}
unzipped_patch = malloc(the_unzipped_len);
if (!unzipped_patch) {
ERROR();
}
/* read the zipped patch4blk */
if (ota_flash_read(patch, zipped_patch, the_zipped_len) != 0) {
ERROR();
}
patch += the_zipped_len;
patchsize -= the_zipped_len;
if (patchsize <= 0) {
ERROR();
}
/* do unzip */
if (lzma_uncompress(unzipped_patch, &the_unzipped_len, zipped_patch, &the_zipped_len) != LZMA_ERR_OK) {
ERROR();
}
free(zipped_patch);
/*
format of patch for one block:
0 2 I block index of the patch
2 2 N count of cmd
4 2 C sizeof(control block)
6 2 D sizeof(diff block)
6 C control block
6 + C D diff block
6 + C + D ? extra block
*/
/* control block:
with a leading 8bit domain, indicating the cmd type, 0 for DIFF, 1 for EXTRA
if current is a CMD_COPY(X, Y, Z) cmd:
X is 0(COPY)
locate old to Z, copy Y bytes from oldfile
if current is a CMD_DIFF(X, Y, Z) cmd:
X is 1(DIFF)
locate old to Z, add Y bytes from oldfile to Y bytes from the diff block
if current is a CMD_EXTRA(X, Y) cmd:
X is 2(EXTRA)
copy Y bytes from the extra block
*/
/* here the show begins */
/* read the patch4info */
patch4blk_info = (patch4blk_info_t *)unzipped_patch;
I = patch4blk_info->blk_idx;
N = patch4blk_info->cmd_cnt;
C = patch4blk_info->ctrl_size;
D = patch4blk_info->diff_size;
ctrl_blk = unzipped_patch + sizeof(patch4blk_info_t);
diff_blk = unzipped_patch + sizeof(patch4blk_info_t) + C;
extra_blk = unzipped_patch + sizeof(patch4blk_info_t) + C + D;
cursor = 0;
memset(block, 0, blk_len);
/* backup the old block I first */
if (!ota_partition_is_pingpong() &&
backup_map_add(&bkup_map, I,
THE_BUF(ota_partition_start(OTA_PARTITION_ACTIVE_APP), I, blk_len),
blk_buf) != 0) {
ERROR();
}
while (N--) {
X = *(uint8_t *)ctrl_blk;
ctrl_blk += 1;
if (X == CMD_COPY || X == CMD_DIFF) { // a COPY or DIFF cmd
Y = offtin_u16(ctrl_blk);
ctrl_blk += sizeof(uint16_t);
Z = offtin_u16(ctrl_blk);
ctrl_blk += sizeof(uint16_t);
old_idx = BLK_IDX(Z, blk_len);
old_offset = Z - BLK_LOWER_BOUND(old_idx, blk_len);
/* sanity check */
if (BLK_IDX(cursor + Y - 1, blk_len) != BLK_IDX(cursor, blk_len)) {
ERROR();
}
if (ota_partition_is_pingpong()) {
// if pingpong, copy from OTA_PARTITION_BACKUP_APP
if (ota_flash_read(THE_BUF(ota_partition_start(OTA_PARTITION_BACKUP_APP), old_idx, blk_len),
blk_buf, blk_len) != 0) {
ERROR();
}
} else {
res = backup_map_query(&bkup_map, old_idx, blk_buf);
if (res == QUERY_RESULT_FETCH_FAILED) {
ERROR();
}
if (res == QUERY_RESULT_NOT_EXIST) {
if (ota_flash_read(THE_BUF(ota_partition_start(OTA_PARTITION_ACTIVE_APP), old_idx, blk_len),
blk_buf, blk_len) != 0) {
ERROR();
}
}
}
memcpy(block + cursor, blk_buf + old_offset, Y);
if (X == CMD_DIFF) {
for (i = 0; i < Y; ++i) {
(block + cursor)[i] += *(int8_t *)(diff_blk + i);
}
diff_blk += Y;
}
} else if (X == CMD_EXTRA) {
Y = offtin_u16(ctrl_blk);
ctrl_blk += sizeof(uint16_t);
/* sanity check */
if (BLK_IDX(cursor + Y - 1, blk_len) != BLK_IDX(cursor, blk_len)) {
ERROR();
}
memcpy(block + cursor, extra_blk, Y);
extra_blk += Y;
} else {
ERROR();
}
cursor += Y;
/* sanity check */
if (cursor > blk_len) {
ERROR();
}
}
free(unzipped_patch);
if (ota_flash_erase(THE_BUF(ota_partition_start(OTA_PARTITION_ACTIVE_APP), I, blk_len), blk_len) != 0) {
ERROR();
}
if (ota_flash_write(THE_BUF(ota_partition_start(OTA_PARTITION_ACTIVE_APP), I, blk_len), block, blk_len) != 0) {
ERROR();
}
}
OUT:
FREE(block);
FREE(blk_buf);
if (!ota_partition_is_pingpong()) {
backup_map_destroy(&bkup_map);
}
return rc;
}

View File

@@ -0,0 +1,334 @@
/*----------------------------------------------------------------------------
* Tencent is pleased to support the open source community by making TencentOS
* available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
* If you have downloaded a copy of the TencentOS binary from Tencent, please
* note that the TencentOS binary is licensed under the BSD 3-Clause License.
*
* If you have downloaded a copy of the TencentOS source code from Tencent,
* please note that TencentOS source code is licensed under the BSD 3-Clause
* License, except for the third-party components listed below which are
* subject to different license terms. Your integration of TencentOS into your
* own projects may require compliance with the BSD 3-Clause License, as well
* as the other licenses applicable to the third-party components included
* within TencentOS.
*---------------------------------------------------------------------------*/
#include "ota_patch.h"
#include "ota_flash.h"
#include "ota_partition.h"
#include "lzma_uncompress.h"
static uint16_t offtin_u16(uint8_t *buf)
{
int32_t y;
y = buf[1];
y = y * 256; y += buf[0];
return y;
}
static int backup_map_create(bkup_map_t *bkup_map, size_t ota_size, uint16_t blk_len)
{
uint16_t i = 0;
uint16_t *cache;
uint16_t remain_blk_cnt;
uint32_t start;
size_t remain_size;
if (ota_partition_size(OTA_PARTITION_OTA) <= ALIGN_UP(ota_size, blk_len)) {
return -1;
}
remain_size = ota_partition_size(OTA_PARTITION_OTA) - ALIGN_UP(ota_size, blk_len);
remain_blk_cnt = BLK_CNT(remain_size, blk_len);
start = ota_partition_start(OTA_PARTITION_OTA) + ALIGN_UP(ota_size, blk_len);
cache = malloc(remain_blk_cnt * sizeof(uint16_t));
if (cache == NULL) {
return -1;
}
for (i = 0; i < remain_blk_cnt; ++i) {
cache[i] = (uint16_t)-1;
}
bkup_map->cache = cache;
bkup_map->backup_n = remain_blk_cnt;
bkup_map->blk_len = blk_len;
bkup_map->start = start;
bkup_map->cursor =0;
return 0;
}
static int backup_map_destroy(bkup_map_t *bkup_map)
{
free(bkup_map->cache);
return 0;
}
static int backup_map_add(bkup_map_t *bkup_map, uint16_t blk_idx, uint32_t backup_ed_addr)
{
uint16_t slot = bkup_map->cursor;
uint16_t blk_len = bkup_map->blk_len;
uint32_t backup_ee_addr = THE_BUF(bkup_map->start, slot, bkup_map->blk_len);
if (ota_flash_erase(backup_ee_addr, blk_len) != 0) {
return -1;
}
if (ota_flash_write(backup_ee_addr, (uint8_t *)backup_ed_addr, blk_len) != 0) {
return -1;
}
bkup_map->cache[slot] = blk_idx;
bkup_map->cursor = (slot + 1) % bkup_map->backup_n;
return 0;
}
static query_res_t backup_map_query(bkup_map_t *bkup_map, uint16_t blk_idx, uint32_t *backup_ee_addr)
{
uint16_t i = 0;
uint16_t blk_len = bkup_map->blk_len;
for (i = 0; i < bkup_map->backup_n; ++i) {
if (bkup_map->cache[i] == blk_idx) {
*backup_ee_addr = THE_BUF(bkup_map->start, i, blk_len);
return QUERY_RESULT_OK;
}
}
return QUERY_RESULT_NOT_EXIST;
}
int ota_patch_xip(uint8_t *patch, size_t patchsize, size_t ota_size)
{
int rc = 0, i = 0;
/* the patch information stuff */
uint8_t *block = NULL;
uint8_t *unzipped_patch = NULL, *zipped_patch = NULL;
uint16_t blk_len, blk_cnt;
uint16_t unzipped_len, zipped_len;
size_t the_unzipped_len, the_zipped_len;
/* the backup stuff */
bkup_map_t bkup_map;
query_res_t res;
uint32_t backup_ee_addr;
/* the patch4blk stuff */
uint8_t X;
uint16_t I, N, Y, Z, C, D;
uint8_t *ctrl_blk, *diff_blk, *extra_blk;
uint16_t cursor = 0;
uint16_t old_idx, old_offset;
patch_hdr_t patch_hdr;
patch4blk_hdr_t patch4blk_hdr;
patch4blk_info_t *patch4blk_info;
/*
format of patch:
patch_hdr + (patch4blk_hdr + zipped(patch4blk)) * N
patch_hdr:
0 2 length of one block
4 2 total count of blocks in the patch
patch4blk_hdr:
4 2 original length of the patch
8 2 zipped length of the patch
*/
/* read the patch header */
memcpy(&patch_hdr, patch, sizeof(patch_hdr_t));
patch += sizeof(patch_hdr_t);
patchsize -= sizeof(patch_hdr_t);
if (patchsize <= 0) {
ERROR();
}
blk_len = patch_hdr.blk_len;
blk_cnt = patch_hdr.blk_cnt;
/* create backup map to cache old blocks */
if (!ota_partition_is_pingpong() &&
backup_map_create(&bkup_map, ota_size, blk_len) != 0) {
ERROR();
}
block = malloc(blk_len);
if (!block) {
ERROR();
}
while (blk_cnt--) {
/* read the patch4blk header */
memcpy(&patch4blk_hdr, patch, sizeof(patch4blk_hdr_t));
patch += sizeof(patch4blk_hdr_t);
patchsize -= sizeof(patch4blk_hdr_t);
if (patchsize <= 0) {
ERROR();
}
unzipped_len = patch4blk_hdr.unzipped_len;
zipped_len = patch4blk_hdr.zipped_len;
the_unzipped_len = unzipped_len;
the_zipped_len = zipped_len;
/* some malloc */
unzipped_patch = malloc(the_unzipped_len);
if (!unzipped_patch) {
ERROR();
}
/* read the zipped patch4blk */
zipped_patch = patch;
patch += the_zipped_len;
patchsize -= the_zipped_len;
if (patchsize <= 0) {
ERROR();
}
/* do unzip */
if (lzma_uncompress(unzipped_patch, &the_unzipped_len, zipped_patch, &the_zipped_len) != LZMA_ERR_OK) {
ERROR();
}
/*
format of patch for one block:
0 2 I block index of the patch
2 2 N count of cmd
4 2 C sizeof(control block)
6 2 D sizeof(diff block)
6 C control block
6 + C D diff block
6 + C + D ? extra block
*/
/* control block:
with a leading 8bit domain, indicating the cmd type, 0 for DIFF, 1 for EXTRA
if current is a CMD_COPY(X, Y, Z) cmd:
X is 0(COPY)
locate old to Z, copy Y bytes from oldfile
if current is a CMD_DIFF(X, Y, Z) cmd:
X is 1(DIFF)
locate old to Z, add Y bytes from oldfile to Y bytes from the diff block
if current is a CMD_EXTRA(X, Y) cmd:
X is 2(EXTRA)
copy Y bytes from the extra block
*/
/* here the show begins */
/* read the patch4info */
patch4blk_info = (patch4blk_info_t *)unzipped_patch;
I = patch4blk_info->blk_idx;
N = patch4blk_info->cmd_cnt;
C = patch4blk_info->ctrl_size;
D = patch4blk_info->diff_size;
ctrl_blk = unzipped_patch + sizeof(patch4blk_info_t);
diff_blk = unzipped_patch + sizeof(patch4blk_info_t) + C;
extra_blk = unzipped_patch + sizeof(patch4blk_info_t) + C + D;
cursor = 0;
memset(block, 0, blk_len);
/* backup the old block I first */
if (!ota_partition_is_pingpong() &&
backup_map_add(&bkup_map, I,
THE_BUF(ota_partition_start(OTA_PARTITION_ACTIVE_APP), I, blk_len)) != 0) {
ERROR();
}
while (N--) {
X = *(uint8_t *)ctrl_blk;
ctrl_blk += 1;
if (X == CMD_COPY || X == CMD_DIFF) { // a COPY or DIFF cmd
Y = offtin_u16(ctrl_blk);
ctrl_blk += sizeof(uint16_t);
Z = offtin_u16(ctrl_blk);
ctrl_blk += sizeof(uint16_t);
old_idx = BLK_IDX(Z, blk_len);
old_offset = Z - BLK_LOWER_BOUND(old_idx, blk_len);
/* sanity check */
if (BLK_IDX(cursor + Y - 1, blk_len) != BLK_IDX(cursor, blk_len)) {
ERROR();
}
if (ota_partition_is_pingpong()) {
// if pingpong, copy from OTA_PARTITION_BACKUP_APP
memcpy(block + cursor, THE_BUF((uint8_t *)ota_partition_start(OTA_PARTITION_BACKUP_APP), old_idx, blk_len) + old_offset, Y);
} else {
res = backup_map_query(&bkup_map, old_idx, &backup_ee_addr);
if (res == QUERY_RESULT_NOT_EXIST) {
// not in the backup, copy from old
memcpy(block + cursor, THE_BUF((uint8_t *)ota_partition_start(OTA_PARTITION_ACTIVE_APP), old_idx, blk_len) + old_offset, Y);
} else { // QUERY_RESULT_NOT_OK
memcpy(block + cursor, (uint8_t *)backup_ee_addr + old_offset, Y);
}
}
if (X == CMD_DIFF) {
for (i = 0; i < Y; ++i) {
(block + cursor)[i] += *(int8_t *)(diff_blk + i);
}
diff_blk += Y;
}
} else if (X == CMD_EXTRA) {
Y = offtin_u16(ctrl_blk);
ctrl_blk += sizeof(uint16_t);
/* sanity check */
if (BLK_IDX(cursor + Y - 1, blk_len) != BLK_IDX(cursor, blk_len)) {
ERROR();
}
memcpy(block + cursor, extra_blk, Y);
extra_blk += Y;
} else {
ERROR();
}
cursor += Y;
/* sanity check */
if (cursor > blk_len) {
ERROR();
}
}
free(unzipped_patch);
if (ota_flash_erase(THE_BUF(ota_partition_start(OTA_PARTITION_ACTIVE_APP), I, blk_len), blk_len) != 0) {
ERROR();
}
if (ota_flash_write(THE_BUF(ota_partition_start(OTA_PARTITION_ACTIVE_APP), I, blk_len), block, blk_len) != 0) {
ERROR();
}
}
OUT:
FREE(block);
if (!ota_partition_is_pingpong()) {
backup_map_destroy(&bkup_map);
}
return rc;
}

View File

@@ -0,0 +1,193 @@
/*----------------------------------------------------------------------------
* Tencent is pleased to support the open source community by making TencentOS
* available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
* If you have downloaded a copy of the TencentOS binary from Tencent, please
* note that the TencentOS binary is licensed under the BSD 3-Clause License.
*
* If you have downloaded a copy of the TencentOS source code from Tencent,
* please note that TencentOS source code is licensed under the BSD 3-Clause
* License, except for the third-party components listed below which are
* subject to different license terms. Your integration of TencentOS into your
* own projects may require compliance with the BSD 3-Clause License, as well
* as the other licenses applicable to the third-party components included
* within TencentOS.
*---------------------------------------------------------------------------*/
#include "tos_k.h"
#include "tos_kv.h"
#include "crc8.h"
#include "ota_flash.h"
#include "ota_partition.h"
#include "ota_image.h"
#include "ota_info.h"
#include "ota_env.h"
#include "lzma_uncompress.h"
#include "ota_recovery.h"
#define MIN(a, b) ((a) < (b) ? (a) : (b))
static int patch_verify(ota_img_hdr_t *img_hdr)
{
#define BUF_SIZE 128
static uint8_t buf[BUF_SIZE];
uint8_t crc = 0;
ota_img_vs_t new_version;
ota_img_vs_t cur_version;
size_t version_len, remain_len, read_len;
uint32_t active_app_start = ota_partition_start(OTA_PARTITION_ACTIVE_APP);
uint32_t patch_start = ota_partition_start(OTA_PARTITION_OTA);
/* drag the ota_img_hdr out of the flash */
if (ota_flash_read(patch_start, img_hdr, sizeof(ota_img_hdr_t)) < 0) {
return -1;
}
/* 1. check whether new version patch downloaded */
if (tos_kv_get("new_version", &new_version, sizeof(ota_img_vs_t), &version_len) != KV_ERR_NONE) {
return -1;
}
if (new_version.major != img_hdr->new_version.major ||
new_version.minor != img_hdr->new_version.minor) {
return -1;
}
/* 2. verify magic */
if (img_hdr->magic != OTA_IMAGE_MAGIC) {
return -1;
}
/* 3. is this patch for current version? */
cur_version = ota_info_curr_version();
if (cur_version.major != img_hdr->old_version.major ||
cur_version.minor != img_hdr->old_version.minor) {
return -1;
}
/* 4. verify the patch crc checksum */
remain_len = img_hdr->patch_size;
crc = ota_img_hdr_crc(img_hdr);
patch_start += sizeof(ota_img_hdr_t);
while (remain_len > 0) {
read_len = MIN(sizeof(buf), remain_len);
if (ota_flash_read(patch_start, buf, read_len) < 0) {
return -1;
}
crc = crc8(crc, buf, read_len);
remain_len -= read_len;
patch_start += read_len;
}
if (crc != img_hdr->patch_crc) {
return -1;
}
/* 5. verify the old crc checksum */
remain_len = img_hdr->old_size;
crc = 0;
while (remain_len > 0) {
read_len = MIN(sizeof(buf), remain_len);
if (ota_flash_read(active_app_start, buf, read_len) < 0) {
return -1;
}
crc = crc8(crc, buf, read_len);
remain_len -= read_len;
active_app_start += read_len;
}
if (crc != img_hdr->old_crc) {
return -1;
}
return 0;
}
static int do_recovery(ota_img_hdr_t *hdr)
{
uint32_t patch = ota_partition_start(OTA_PARTITION_OTA) + sizeof(ota_img_hdr_t);
return ota_patch(patch, hdr->patch_size - sizeof(ota_img_hdr_t), hdr->patch_size);
}
static int app_copy(uint32_t dst, uint32_t dst_size, uint32_t src, uint32_t src_size)
{
#define BUF_SIZE 128
static uint8_t buf[BUF_SIZE];
size_t read_len = 0;
size_t remain_len = src_size;
uint32_t r_addr = src, w_addr = dst;
if (src_size != dst_size) {
return -1;
}
/* make flash ready */
if (ota_flash_erase_blocks(dst, dst_size) < 0) {
return -1;
}
while (remain_len > 0) {
read_len = MIN(sizeof(buf), remain_len);
if (ota_flash_read(r_addr, buf, read_len) < 0) {
return -1;
}
if (ota_flash_write(w_addr, (void *)buf, ota_flash_write_size_aligned_get(read_len)) < 0) {
return -1;
}
w_addr += read_len;
r_addr += read_len;
remain_len -= read_len;
}
return 0;
}
int ota_recovery(void)
{
ota_img_hdr_t img_hdr;
if (patch_verify(&img_hdr)) {
return -1;
}
/* backup */
if (ota_partition_is_pingpong() &&
app_copy(ota_partition_start(OTA_PARTITION_BACKUP_APP),
ota_partition_size(OTA_PARTITION_BACKUP_APP),
ota_partition_start(OTA_PARTITION_ACTIVE_APP),
ota_partition_size(OTA_PARTITION_ACTIVE_APP)) < 0) {
return -1;
}
if (do_recovery(&img_hdr) != 0) {
printf("recovery failed\n");
/* restore */
if (ota_partition_is_pingpong()) {
app_copy(ota_partition_start(OTA_PARTITION_ACTIVE_APP),
ota_partition_size(OTA_PARTITION_ACTIVE_APP),
ota_partition_start(OTA_PARTITION_BACKUP_APP),
ota_partition_size(OTA_PARTITION_BACKUP_APP));
}
return -1;
}
if (ota_info_update(img_hdr.new_version) != 0) {
return -1;
}
return 0;
}

View File

@@ -0,0 +1,152 @@
/*----------------------------------------------------------------------------
* Tencent is pleased to support the open source community by making TencentOS
* available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
* If you have downloaded a copy of the TencentOS binary from Tencent, please
* note that the TencentOS binary is licensed under the BSD 3-Clause License.
*
* If you have downloaded a copy of the TencentOS source code from Tencent,
* please note that TencentOS source code is licensed under the BSD 3-Clause
* License, except for the third-party components listed below which are
* subject to different license terms. Your integration of TencentOS into your
* own projects may require compliance with the BSD 3-Clause License, as well
* as the other licenses applicable to the third-party components included
* within TencentOS.
*---------------------------------------------------------------------------*/
#include "tos_k.h"
#include "tos_kv.h"
#include "crc8.h"
#include "ota_flash.h"
#include "ota_partition.h"
#include "ota_image.h"
#include "ota_info.h"
#include "ota_env.h"
#include "lzma_uncompress.h"
#include "ota_recovery.h"
static int patch_verify(ota_img_hdr_t *img_hdr)
{
uint8_t crc = 0;
size_t version_len;
ota_img_vs_t new_version;
ota_img_vs_t cur_version;
/* read the ota_img_hdr */
memcpy(img_hdr, (void *)(ota_partition_start(OTA_PARTITION_OTA)), sizeof(ota_img_hdr_t));
/* 1. check whether new version patch downloaded */
if (tos_kv_get("new_version", &new_version, sizeof(new_version), &version_len) != KV_ERR_NONE) {
return -1;
}
if (new_version.major != img_hdr->new_version.major ||
new_version.minor != img_hdr->new_version.minor) {
return -1;
}
/* 2. verify magic */
if (img_hdr->magic != OTA_IMAGE_MAGIC) {
return -1;
}
/* 3. is this patch for current version? */
cur_version = ota_info_curr_version();
if (cur_version.major != img_hdr->old_version.major ||
cur_version.minor != img_hdr->old_version.minor) {
return -1;
}
/* 4. verify the patch crc checksum */
crc = ota_img_hdr_crc(img_hdr);
crc = crc8(crc, (uint8_t *)(ota_partition_start(OTA_PARTITION_OTA) + sizeof(ota_img_hdr_t)), img_hdr->patch_size);
if (crc != img_hdr->patch_crc) {
return -1;
}
/* 5. verify the old crc checksum */
crc = crc8(0, (uint8_t *)ota_partition_start(OTA_PARTITION_ACTIVE_APP), img_hdr->old_size);
if (crc != img_hdr->old_crc) {
return -1;
}
return 0;
}
static int do_recovery_xip(ota_img_hdr_t *hdr)
{
uint8_t *patch = (uint8_t *)(ota_partition_start(OTA_PARTITION_OTA) + sizeof(ota_img_hdr_t));
return ota_patch_xip(patch, hdr->patch_size - sizeof(ota_img_hdr_t), hdr->patch_size);
}
static int app_copy(uint32_t dst, uint32_t dst_size, uint32_t src, uint32_t src_size)
{
size_t read_len = 0;
size_t remain_len = src_size;
uint32_t r_addr = src, w_addr = dst;
if (src_size != dst_size) {
return -1;
}
/* make flash ready */
if (ota_flash_erase_blocks(dst, dst_size) < 0) {
return -1;
}
#define MIN(a, b) ((a) < (b) ? (a) : (b))
while (remain_len > 0) {
read_len = MIN(remain_len, 128);
if (ota_flash_write(w_addr, (void *)r_addr, ota_flash_write_size_aligned_get(read_len)) < 0) {
return -1;
}
w_addr += read_len;
r_addr += read_len;
remain_len -= read_len;
}
return 0;
}
int ota_recovery_xip(void)
{
ota_img_hdr_t img_hdr;
if (patch_verify(&img_hdr)) {
return -1;
}
/* backup */
if (ota_partition_is_pingpong() &&
app_copy(ota_partition_start(OTA_PARTITION_BACKUP_APP),
ota_partition_size(OTA_PARTITION_BACKUP_APP),
ota_partition_start(OTA_PARTITION_ACTIVE_APP),
ota_partition_size(OTA_PARTITION_ACTIVE_APP)) < 0) {
return -1;
}
if (do_recovery_xip(&img_hdr) != 0) {
printf("recovery failed\n");
/* restore */
if (ota_partition_is_pingpong()) {
app_copy(ota_partition_start(OTA_PARTITION_ACTIVE_APP),
ota_partition_size(OTA_PARTITION_ACTIVE_APP),
ota_partition_start(OTA_PARTITION_BACKUP_APP),
ota_partition_size(OTA_PARTITION_BACKUP_APP));
}
return -1;
}
if (ota_info_update(img_hdr.new_version) != 0) {
return -1;
}
return 0;
}