project:cfg:BoardConfig_IPC: Added fastboot BoardConfig file and firmware post-scripts, distinguishing between the BoardConfigs for Luckfox Pico Pro and Luckfox Pico Max. project:app: Added fastboot_client and rk_smart_door for quick boot applications; updated rkipc app to adapt to the latest media library. media:samples: Added more usage examples. media:rockit: Fixed bugs; removed support for retrieving data frames from VPSS. media:isp: Updated rkaiq library and related tools to support connection to RKISP_Tuner. sysdrv:Makefile: Added support for compiling drv_ko on Luckfox Pico Ultra W using Ubuntu; added support for custom root filesystem. sysdrv:tools:board: Updated Buildroot optional mirror sources, updated some software versions, and stored device tree files and configuration files that undergo multiple modifications for U-Boot and kernel separately. sysdrv:source:mcu: Used RISC-V MCU SDK with RT-Thread system, mainly for initializing camera AE during quick boot. sysdrv:source:uboot: Added support for fastboot; added high baud rate DDR bin for serial firmware upgrades. sysdrv:source:kernel: Upgraded to version 5.10.160; increased NPU frequency for RV1106G3; added support for fastboot. Signed-off-by: luckfox-eng29 <eng29@luckfox.com>
1234 lines
33 KiB
C
1234 lines
33 KiB
C
/**
|
|
* Copyright (c) 2020 Fuzhou Rockchip Electronics Co., Ltd
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <rtdevice.h>
|
|
#include <rtthread.h>
|
|
|
|
#include <dfs_posix.h>
|
|
#include <drivers/mtd_nor.h>
|
|
#include "hal_base.h"
|
|
#include "hal_bsp.h"
|
|
|
|
#ifdef RT_USING_OTA
|
|
#include "../fwmgr/fw_analysis.h"
|
|
#include "../fwmgr/rkpart.h"
|
|
#include "drv_flash_partition.h"
|
|
|
|
#include "ota_opt.h"
|
|
//#include "ota_debug.h"
|
|
#ifdef RT_USING_OTA_FROM_LOCAL
|
|
#include "ota_file.h"
|
|
#endif
|
|
|
|
#ifdef RT_USING_OTA_FROM_HTTP
|
|
#include "ota_http.h"
|
|
#endif
|
|
|
|
#include "ota.h"
|
|
|
|
#define DBG_SECTION_NAME "OTA"
|
|
#include "rkdebug.h"
|
|
|
|
#define OTA_IMG_DATA_CORRUPTION_TEST 0
|
|
#define OTA_UPDATE_DEBUG_UNIT (50 * 1024)
|
|
|
|
rt_uint32_t g_fw_curr_slot; /* current fw run in slot */
|
|
rt_uint32_t g_user_curr_slot; /* current userdata used slot */
|
|
rt_uint32_t g_os_real_size; /* os part real size */
|
|
rt_uint32_t g_data_real_size; /* data part real size */
|
|
rt_uint32_t g_root_real_size; /* userdata part real size */
|
|
|
|
static ota_priv_st ota_priv;
|
|
|
|
/* alloc 1M buffer to save fw data from http server*/
|
|
//#define OTA_FW_DATA_SIZE (1024*1024)
|
|
//static char *gOtaFwBuff;
|
|
|
|
/* indexed by image_seq_t */
|
|
static const rt_uint8_t ota_update_seq_policy[IMAGE_SEQ_NUM] =
|
|
{
|
|
#if (IMAGE_SEQ_NUM == 2)
|
|
/* update policy: 0 -> 1, 1 -> 0 */
|
|
1, 0
|
|
#elif (IMAGE_SEQ_NUM == 3)
|
|
/* update policy: 0 -> 1, 1 -> 2, 2 -> 1 */
|
|
1, 2, 1
|
|
#else
|
|
#error "unsupport image seq num!"
|
|
#endif
|
|
};
|
|
|
|
static struct rt_mtd_nor_device *snor_device = RT_NULL;
|
|
|
|
static rt_uint8_t ota_get_update_seq(void)
|
|
{
|
|
rt_uint8_t seq = IMAGE_SEQ_NUM;
|
|
|
|
if (ota_priv.fw_running_slot >= IMAGE_SEQ_NUM)
|
|
{
|
|
LOGE("not init, running slot ## %s ##\n", ota_priv.fw_running_slot ? "A" : "B");
|
|
return seq;
|
|
}
|
|
|
|
seq = ota_update_seq_policy[ota_priv.fw_running_slot]; /* update sequence */
|
|
LOGD("%s(), update seq %d\n", __func__, seq);
|
|
return seq;
|
|
}
|
|
|
|
/**
|
|
* @brief Initialize the OTA service
|
|
* @retval ota_status_t, OTA_STATUS_OK on success
|
|
*/
|
|
ota_status ota_init(void)
|
|
{
|
|
int32_t ret;
|
|
rt_uint32_t fw_slot_boot;
|
|
#ifdef RT_SUPPORT_ROOT_AB
|
|
rt_uint32_t user_slot_boot;
|
|
#endif
|
|
const char *slot_name[2] = {"A", "B"};
|
|
rt_uint32_t part_total_num = 0;
|
|
struct rt_flash_partition *part_info = RT_NULL;
|
|
|
|
snor_device = (struct rt_mtd_nor_device *)rt_device_find("snor");
|
|
if (snor_device == RT_NULL)
|
|
{
|
|
LOGE("Did not find device: snor...");
|
|
return OTA_STATUS_ERR;
|
|
}
|
|
|
|
part_total_num = get_rk_partition(&part_info);
|
|
RT_ASSERT(part_info);
|
|
|
|
for (int i = 0; i < part_total_num; i++)
|
|
{
|
|
if (part_info[i].type == PART_FW1)
|
|
{
|
|
firmware_addr1 = part_info[i].offset;
|
|
fw_part_size1 = part_info[i].size;
|
|
LOGI("%s :", part_info[i].name);
|
|
LOGI("FW1: Addr:0x%x, size:%d (0x%x sector)", firmware_addr1,
|
|
fw_part_size1, fw_part_size1 >> 9);
|
|
|
|
}
|
|
else if (part_info[i].type == PART_FW2)
|
|
{
|
|
firmware_addr2 = part_info[i].offset;
|
|
fw_part_size2 = part_info[i].size;
|
|
LOGI("%s :", part_info[i].name);
|
|
LOGI("FW2:Addr:0x%x, size:%d (0x%x sector)", firmware_addr2,
|
|
fw_part_size2, fw_part_size2 >> 9);
|
|
}
|
|
else if (part_info[i].type == PART_DATA)
|
|
{
|
|
data_start_addr = part_info[i].offset;
|
|
data_part_size = part_info[i].size;
|
|
LOGI("%s :", part_info[i].name);
|
|
LOGI("DATA:Addr:0x%x, size:%d (0x%x sector)", data_start_addr,
|
|
data_part_size, data_part_size >> 9);
|
|
}
|
|
else if (part_info[i].type == PART_USER1)
|
|
{
|
|
user_start_addr1 = part_info[i].offset;
|
|
user_part_size = part_info[i].size;
|
|
|
|
LOGI("%s :", part_info[i].name);
|
|
LOGI("USER1:Addr:0x%x, size :%d (0x%x sectors)", user_start_addr1,
|
|
user_part_size, user_part_size >> 9);
|
|
}
|
|
else if (part_info[i].type == PART_USER2)
|
|
{
|
|
user_start_addr2 = part_info[i].offset;
|
|
user_part_size = part_info[i].size;
|
|
|
|
LOGI("%s :", part_info[i].name);
|
|
LOGI("USER2:Addr:0x%x, size :%d (0x%x sectors)", user_start_addr2,
|
|
user_part_size, user_part_size >> 9);
|
|
}
|
|
}
|
|
|
|
ret = fw_slot_get_current_running(&fw_slot_boot);
|
|
if (ret != OTA_STATUS_OK)
|
|
return OTA_STATUS_ERR;
|
|
|
|
rt_memset(&ota_priv, 0, sizeof(ota_priv));
|
|
if (fw_slot_boot == 0)
|
|
ota_priv.os_addr = firmware_addr2;
|
|
else if (fw_slot_boot == 1)
|
|
ota_priv.os_addr = firmware_addr1;
|
|
else
|
|
return OTA_STATUS_ERR;
|
|
|
|
LOGI("%s : will update os addr:0x%08x", __func__, ota_priv.os_addr);
|
|
|
|
ota_priv.fw_running_slot = fw_slot_boot;
|
|
g_fw_curr_slot = fw_slot_boot;
|
|
LOGD("=== Current rt-thread running %s slot fw ===", slot_name[fw_slot_boot]);
|
|
|
|
if (fw_slot_boot == 0)
|
|
{
|
|
ota_priv.img_max_size = fw_part_size2;
|
|
ota_priv.data_max_size = 0;
|
|
ota_priv.data_addr = data_start_addr;
|
|
}
|
|
else if (fw_slot_boot == 1)
|
|
{
|
|
ota_priv.img_max_size = fw_part_size1;
|
|
ota_priv.data_max_size = data_part_size;
|
|
ota_priv.data_addr = data_start_addr;
|
|
}
|
|
|
|
LOGD("%s():os img size = %u(0x%#x sectors)", __func__, ota_priv.img_max_size,
|
|
ota_priv.img_max_size >> 9);
|
|
|
|
#ifdef RT_SUPPORT_ROOT_AB
|
|
ret = user_slot_get_current_running(&user_slot_boot);
|
|
if (ret != OTA_STATUS_OK)
|
|
return OTA_STATUS_ERR;
|
|
|
|
if (user_slot_boot == 0)
|
|
ota_priv.user_addr = user_start_addr2;
|
|
else if (user_slot_boot == 1)
|
|
ota_priv.user_addr = user_start_addr1;
|
|
else
|
|
return OTA_STATUS_ERR;
|
|
|
|
rt_kprintf("%s : will update user addr:0x%08x\n", __func__, ota_priv.user_addr);
|
|
|
|
ota_priv.user_running_slot = user_slot_boot;
|
|
g_user_curr_slot = user_slot_boot;
|
|
LOGD(" === Current user running %s slot ===", slot_name[user_slot_boot]);
|
|
|
|
ota_priv.user_max_size = user_part_size;
|
|
LOGD("%s(): userdata img size = %u(%#x)", __func__, ota_priv.user_max_size,
|
|
ota_priv.user_max_size);
|
|
#endif
|
|
|
|
return OTA_STATUS_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief DeInitialize the OTA service
|
|
* @return None
|
|
*/
|
|
void ota_deinit(void)
|
|
{
|
|
rt_memset(&ota_priv, 0, sizeof(ota_priv));
|
|
}
|
|
|
|
/* update os partiton process */
|
|
static ota_status ota_update_os_proc(rt_uint8_t *ota_buf, rt_uint8_t *fw_buf,
|
|
ota_update_get get_cb)
|
|
{
|
|
uint32_t os_addr;
|
|
uint32_t os_size;
|
|
uint32_t debug_size;
|
|
uint32_t write_size;
|
|
rt_uint8_t eof_flag;
|
|
|
|
ota_status ret = OTA_STATUS_ERR;
|
|
ota_status status = OTA_STATUS_ERR;
|
|
|
|
os_size = ota_priv.img_max_size;
|
|
os_addr = ota_priv.os_addr;
|
|
debug_size = OTA_UPDATE_DEBUG_UNIT;
|
|
|
|
LOGD("%s(), request to update seq %d, will update fw start addr 0x%#x\n",
|
|
__func__, 1 - g_fw_curr_slot, os_addr);
|
|
if (os_addr == 0)
|
|
{
|
|
LOGE("Error: fw%d address is invalide!!!");
|
|
return ret;
|
|
}
|
|
|
|
if (os_size == 0)
|
|
return OTA_STATUS_OK;
|
|
|
|
LOGI("system image max size %u", os_size);
|
|
|
|
/* System Partiton update process */
|
|
LOGI("------------Start update System %s partition------------",
|
|
ota_priv.fw_running_slot == 0 ? "B" : "A");
|
|
rt_kprintf("[OTA] The System partiton update: %2d%%", ota_priv.get_size);
|
|
while (os_size > 0)
|
|
{
|
|
uint32_t len, recvSize;
|
|
len = MINIMUM(os_size, OTA_BUF_SIZE);
|
|
|
|
rt_memset(ota_buf, 0, OTA_BUF_SIZE);
|
|
status = get_cb(ota_buf, len, &recvSize, &eof_flag);
|
|
// LOGD("read from file size = %d", recvSize);
|
|
if (status != OTA_STATUS_OK)
|
|
{
|
|
LOGE("ota file get process status %d\n", status);
|
|
break;
|
|
}
|
|
|
|
rt_memset(fw_buf, 0, OTA_BUF_SIZE);
|
|
rt_memcpy(fw_buf, ota_buf, OTA_BUF_SIZE);
|
|
|
|
//LOGD("next os addr = 0x%x", os_addr);
|
|
rt_mtd_nor_erase_block(snor_device, os_addr, snor_device->block_size);
|
|
write_size = rt_mtd_nor_write(snor_device, os_addr,
|
|
(const rt_uint8_t *)fw_buf, snor_device->block_size);
|
|
if (write_size != snor_device->block_size)
|
|
{
|
|
LOGE("os Fw data %#d write Error!", 1 - g_fw_curr_slot);
|
|
break;
|
|
}
|
|
|
|
os_addr += OTA_BUF_SIZE;
|
|
os_size -= recvSize;
|
|
ota_priv.get_size += recvSize;
|
|
rt_kprintf("\b\b\b%2d%%", (ota_priv.get_size * 100) / g_os_real_size);
|
|
|
|
if (eof_flag)
|
|
{
|
|
ret = OTA_STATUS_OK;
|
|
rt_kprintf("\n\n");
|
|
LOGD("Donwloaded image %u Bytes(%u KB) to End \n",
|
|
ota_priv.get_size, ota_priv.get_size / 1024);
|
|
break;
|
|
}
|
|
|
|
if (ota_priv.get_size >= debug_size)
|
|
{
|
|
//LOGD("OTA: Donwloaded image (%u KB)...", ota_priv.get_size / 1024);
|
|
debug_size += OTA_UPDATE_DEBUG_UNIT;
|
|
}
|
|
|
|
rt_thread_delay(10);
|
|
//LOGD("os_size left = %d\n", os_size);
|
|
}
|
|
|
|
LOGD("finish loading image %d(0x%#08x)", ota_priv.get_size, ota_priv.get_size);
|
|
return ret;
|
|
}
|
|
|
|
/* update data partiton process */
|
|
static ota_status ota_update_data_proc(rt_uint8_t *ota_buf, rt_uint8_t *fw_buf,
|
|
ota_update_get get_cb)
|
|
{
|
|
uint32_t data_addr;
|
|
uint32_t data_size;
|
|
uint32_t debug_size;
|
|
uint32_t write_size;
|
|
rt_uint8_t eof_flag;
|
|
ota_status ret = OTA_STATUS_ERR;
|
|
ota_status status = OTA_STATUS_ERR;
|
|
|
|
ota_priv.get_size = 0;
|
|
data_size = ota_priv.data_max_size;
|
|
data_addr = ota_priv.data_addr;
|
|
debug_size = OTA_UPDATE_DEBUG_UNIT;
|
|
|
|
if (data_size == 0)
|
|
return OTA_STATUS_OK;
|
|
|
|
LOGI("data partiton max size %u", data_size);
|
|
LOGI("------------Start update Data partition------------");
|
|
rt_kprintf("[OTA] The Data partiton update: %2d%%", ota_priv.get_size);
|
|
|
|
while (data_size > 0)
|
|
{
|
|
uint32_t len, recvSize;
|
|
len = MINIMUM(data_size, OTA_BUF_SIZE);
|
|
|
|
rt_memset(ota_buf, 0, OTA_BUF_SIZE);
|
|
status = get_cb(ota_buf, len, &recvSize, &eof_flag);
|
|
// LOGD("read from file size = %d", recvSize);
|
|
if (status != OTA_STATUS_OK)
|
|
{
|
|
LOGE("ota file get process status %d\n", status);
|
|
break;
|
|
}
|
|
|
|
rt_memset(fw_buf, 0, OTA_BUF_SIZE);
|
|
rt_memcpy(fw_buf, ota_buf, OTA_BUF_SIZE);
|
|
|
|
//LOGD("next addr = 0x%x", data_addr);
|
|
rt_mtd_nor_erase_block(snor_device, data_addr, snor_device->block_size);
|
|
write_size = rt_mtd_nor_write(snor_device, data_addr, (const rt_uint8_t *)fw_buf,
|
|
snor_device->block_size);
|
|
if (write_size != snor_device->block_size)
|
|
{
|
|
LOGE("data patition write Error!");
|
|
break;
|
|
}
|
|
|
|
//if (!eof_flag)
|
|
{
|
|
data_addr += OTA_BUF_SIZE;
|
|
data_size -= recvSize;
|
|
ota_priv.get_size += recvSize;
|
|
rt_kprintf("\b\b\b%2d%%", (ota_priv.get_size * 100) / g_data_real_size);
|
|
}
|
|
|
|
if (eof_flag)
|
|
{
|
|
ret = OTA_STATUS_OK;
|
|
rt_kprintf("\n\n");
|
|
LOGD("Donwloaded image %u Bytes(%u KB) to End",
|
|
ota_priv.get_size, ota_priv.get_size / 1024);
|
|
break;
|
|
}
|
|
|
|
if (ota_priv.get_size >= debug_size)
|
|
{
|
|
//LOGD("OTA: Donwloaded image (%u KB)...", ota_priv.get_size / 1024);
|
|
debug_size += OTA_UPDATE_DEBUG_UNIT;
|
|
}
|
|
|
|
rt_thread_delay(10);
|
|
//LOGD("data_size left = %d\n", data_size);
|
|
}
|
|
|
|
LOGD("finish loading image %d(0x%#08x)", ota_priv.get_size, ota_priv.get_size);
|
|
return ret;
|
|
}
|
|
|
|
#ifdef RT_SUPPORT_ROOT_AB
|
|
/* update Userdata partiton process */
|
|
static ota_status ota_update_root_proc(rt_uint8_t *ota_buf, rt_uint8_t *fw_buf,
|
|
ota_update_get get_cb)
|
|
{
|
|
uint32_t user_addr = 0;
|
|
uint32_t user_img_max_size = 0;
|
|
uint32_t debug_size;
|
|
uint32_t write_size;
|
|
rt_uint8_t eof_flag;
|
|
ota_status status = OTA_STATUS_ERR;
|
|
ota_status ret = OTA_STATUS_ERR;
|
|
|
|
user_img_max_size = ota_priv.user_max_size;
|
|
user_addr = ota_priv.user_addr;
|
|
|
|
LOGD("%s(), will update USER %d, will update USER start addr 0x%#x\n", __func__,
|
|
1 - ota_priv.user_running_slot, user_addr);
|
|
if (user_addr == 0)
|
|
{
|
|
LOGE("Error: fw%d address is invalide!!!");
|
|
return ret;
|
|
}
|
|
|
|
ota_priv.user_get_size = 0;
|
|
g_root_real_size = user_part_size;
|
|
LOGI("------------Start update User partition------------");
|
|
rt_kprintf("[OTA] The User partiton update: %2d%%", ota_priv.user_get_size);
|
|
|
|
#ifdef RT_USING_OTA_FROM_HTTP
|
|
ota_start_download_task((void *)1); //create root partition update thread.
|
|
#endif
|
|
|
|
while (user_img_max_size > 0)
|
|
{
|
|
uint32_t len = 0, recvSize = 0;
|
|
len = MINIMUM(user_img_max_size, OTA_BUF_SIZE);
|
|
|
|
rt_memset(ota_buf, 0, OTA_BUF_SIZE);
|
|
|
|
status = get_cb(ota_buf, len, &recvSize, &eof_flag);
|
|
// LOGD("read from file size = %d", recvSize);
|
|
if (status != OTA_STATUS_OK)
|
|
{
|
|
LOGE("ota file get process status %d\n", status);
|
|
break;
|
|
}
|
|
|
|
rt_memset(fw_buf, 0, OTA_BUF_SIZE);
|
|
rt_memcpy(fw_buf, ota_buf, OTA_BUF_SIZE);
|
|
|
|
// LOGD("next addr = 0x%x", user_addr);
|
|
rt_mtd_nor_erase_block(snor_device, user_addr, snor_device->block_size);
|
|
write_size = rt_mtd_nor_write(snor_device, user_addr, (const rt_uint8_t *)fw_buf,
|
|
snor_device->block_size);
|
|
if (write_size != snor_device->block_size)
|
|
{
|
|
LOGE("userdata partiton %#d write Error!", 1 - g_user_curr_slot);
|
|
break;
|
|
}
|
|
|
|
if (!eof_flag)
|
|
{
|
|
user_addr += OTA_BUF_SIZE;
|
|
user_img_max_size -= recvSize;
|
|
ota_priv.user_get_size += recvSize;
|
|
rt_kprintf("\b\b\b%2d%%", (ota_priv.user_get_size * 100) / g_root_real_size);
|
|
}
|
|
else
|
|
{
|
|
ret = OTA_STATUS_OK;
|
|
rt_kprintf("\n\n");
|
|
LOGD("Donwloaded image %u Bytes(%u KB) to End", ota_priv.user_get_size,
|
|
ota_priv.user_get_size / 1024);
|
|
break;
|
|
}
|
|
|
|
if (ota_priv.user_get_size >= debug_size)
|
|
{
|
|
//LOGD("OTA: Donwloaded image (%u KB)...", ota_priv.user_get_size / 1024);
|
|
debug_size += OTA_UPDATE_DEBUG_UNIT;
|
|
}
|
|
|
|
rt_thread_delay(10);
|
|
//LOGD("user_img_max_size left = %d\n", user_img_max_size);
|
|
}
|
|
|
|
#ifdef RT_USING_OTA_FROM_HTTP
|
|
ota_exit_download_task();
|
|
#endif
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
static ota_status ota_update_image_process(uint8_t seq, void *url,
|
|
ota_update_init init_cb,
|
|
ota_update_get get_cb)
|
|
{
|
|
uint8_t *ota_buf;
|
|
ota_status ret = OTA_STATUS_ERR;
|
|
rt_uint8_t *p_fwbuf;
|
|
rt_bool_t bSucc = RT_TRUE;
|
|
|
|
struct rt_mtd_nor_device *snor_device = RT_NULL;
|
|
|
|
snor_device = (struct rt_mtd_nor_device *)rt_device_find("snor");
|
|
if (snor_device == RT_NULL)
|
|
{
|
|
LOGD("Did not find device: snor....");
|
|
return ret;
|
|
}
|
|
|
|
LOGD("block_size = %d", snor_device->block_size);
|
|
|
|
ota_buf = rt_malloc_align(OTA_BUF_SIZE, 4);
|
|
if (ota_buf == RT_NULL)
|
|
{
|
|
LOGE("NO memory!");
|
|
return ret;
|
|
}
|
|
|
|
p_fwbuf = rt_malloc_align(OTA_BUF_SIZE, 64);
|
|
if (p_fwbuf == RT_NULL)
|
|
{
|
|
LOGE("NO memory!!");
|
|
if (ota_buf)
|
|
{
|
|
rt_free(ota_buf);
|
|
ota_buf = RT_NULL;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
if (init_cb(url) != OTA_STATUS_OK)
|
|
{
|
|
LOGE("ota update init failed");
|
|
bSucc = RT_FALSE;
|
|
goto ota_err;
|
|
}
|
|
|
|
#ifdef RT_USING_OTA_FROM_HTTP
|
|
ota_start_download_task((void *)0);
|
|
#endif
|
|
|
|
ret = ota_update_os_proc(ota_buf, p_fwbuf, get_cb);
|
|
if (ret != OTA_STATUS_OK)
|
|
{
|
|
bSucc = RT_FALSE;
|
|
goto ota_err;
|
|
}
|
|
|
|
ret = ota_update_data_proc(ota_buf, p_fwbuf, get_cb);
|
|
if (ret != OTA_STATUS_OK)
|
|
{
|
|
bSucc = RT_FALSE;
|
|
goto ota_err;
|
|
}
|
|
|
|
#ifdef RT_USING_OTA_FROM_HTTP
|
|
ota_exit_download_task();
|
|
#endif
|
|
|
|
#ifdef RT_SUPPORT_ROOT_AB
|
|
ret = ota_update_root_proc(ota_buf, p_fwbuf, get_cb);
|
|
if (ret != OTA_STATUS_OK)
|
|
{
|
|
bSucc = RT_FALSE;
|
|
goto ota_err;
|
|
}
|
|
#endif //RT_SUPPORT_ROOT_AB
|
|
|
|
ota_err:
|
|
if (ota_buf)
|
|
{
|
|
rt_free_align(ota_buf);
|
|
ota_buf = RT_NULL;
|
|
}
|
|
|
|
if (p_fwbuf)
|
|
{
|
|
rt_free_align(p_fwbuf);
|
|
p_fwbuf = RT_NULL;
|
|
}
|
|
|
|
// LOGD("finish loading image %d(0x%#08x)", ota_priv.get_size, ota_priv.get_size);
|
|
|
|
/* do jhash check here before we set slot activity */
|
|
if (bSucc)
|
|
{
|
|
if (ota_verify_img(OTA_VERIFY_JHASH) != OTA_STATUS_OK)
|
|
{
|
|
LOGE("ota check image failed");
|
|
return OTA_STATUS_ERR;
|
|
}
|
|
LOGD("Finish checking os image.\n");
|
|
|
|
/* dsp data and version check,just in fw B to do. */
|
|
if (ota_priv.data_max_size)
|
|
{
|
|
/* Verify data partition firmware : flash data partiton with local file*/
|
|
if (ota_data_check(url) != OTA_STATUS_OK)
|
|
{
|
|
LOGE("ota check data image failed");
|
|
return OTA_STATUS_ERR;
|
|
}
|
|
LOGD("Finish checking data image.\n");
|
|
|
|
if (ota_dsp_version_cmp() != OTA_STATUS_OK)
|
|
{
|
|
LOGE("ota dsp version check failed");
|
|
return OTA_STATUS_ERR;
|
|
}
|
|
LOGD("dsp version is accordant!");
|
|
}
|
|
|
|
if (seq == 1) /* pending os Fw 2 slot*/
|
|
LOGD(" ---- Set system Start from FW2 slot----");
|
|
else if (seq == 0) /* pending os Fw 1 slot*/
|
|
LOGD(" ---- Set system Start from FW1 slot----");
|
|
|
|
fw_slot_set_pending(ota_priv.fw_running_slot);
|
|
|
|
#ifdef RT_SUPPORT_ROOT_AB
|
|
if (g_user_curr_slot == 0) /* pending user fs part 2 slot*/
|
|
LOGD(" ---- Set userdata Start from FW2 slot----");
|
|
else if (g_user_curr_slot == 1) /* pending user fs part 1 slot*/
|
|
LOGD(" ---- Set userdata Start from FW1 slot----");
|
|
user_slot_set_pending(ota_priv.user_running_slot);
|
|
change_part_name((ota_priv.user_running_slot == 1) ? 0x40000000 : 0x80000000, "root");
|
|
change_part_name((ota_priv.user_running_slot == 0) ? 0x40000000 : 0x80000000, "root-old");
|
|
#endif //RT_SUPPORT_ROOT_AB
|
|
}
|
|
else
|
|
{
|
|
#ifdef RT_USING_OTA_FROM_HTTP
|
|
ota_exit_download_task();
|
|
#endif
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* Used for test os firmware upgrade
|
|
* read os fw data from file in url,write os data to update-fw.img in flash
|
|
*/
|
|
RT_UNUSED
|
|
static ota_status ota_update_image_process_test(uint8_t seq, void *url,
|
|
ota_update_init init_cb,
|
|
ota_update_get get_cb)
|
|
{
|
|
uint32_t os_addr = 0;
|
|
uint32_t os_size = 0;
|
|
uint8_t *ota_buf;
|
|
uint8_t eof_flag;
|
|
uint32_t debug_size;
|
|
ota_status status = OTA_STATUS_ERR;
|
|
ota_status ret = OTA_STATUS_ERR;
|
|
rt_bool_t bSucc = RT_TRUE;
|
|
rt_uint8_t *p_fwbuf;
|
|
int test_fd;
|
|
int res;
|
|
|
|
struct rt_mtd_nor_device *snor_device = RT_NULL;
|
|
|
|
snor_device = (struct rt_mtd_nor_device *)rt_device_find("snor");
|
|
if (snor_device == RT_NULL)
|
|
{
|
|
LOGD("Did not find device: snor....");
|
|
return ret;
|
|
}
|
|
|
|
LOGD("block_size = %d", snor_device->block_size);
|
|
|
|
os_size = ota_priv.img_max_size;
|
|
os_addr = ota_priv.os_addr;
|
|
LOGD("%s(), current seq %d, will update fw start addr 0x%#x\n", __func__, seq, os_addr);
|
|
if (os_addr == 0)
|
|
{
|
|
LOGE("Error: fw%d address is invalide!!!");
|
|
return ret;
|
|
}
|
|
|
|
ota_buf = rt_malloc_align(OTA_BUF_SIZE, 4);
|
|
if (ota_buf == RT_NULL)
|
|
{
|
|
LOGE("NO memory!");
|
|
return ret;
|
|
}
|
|
|
|
p_fwbuf = rt_malloc_align(OTA_BUF_SIZE, 64);
|
|
if (p_fwbuf == RT_NULL)
|
|
{
|
|
LOGE("NO memory!!");
|
|
if (ota_buf)
|
|
{
|
|
rt_free(ota_buf);
|
|
ota_buf = RT_NULL;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
test_fd = open("/update-fw.img", O_WRONLY | O_CREAT | O_TRUNC, 0);
|
|
if (test_fd < 0)
|
|
{
|
|
LOGE("ota open file /update-test.img Fail");
|
|
bSucc = RT_FALSE;
|
|
goto ota_err;
|
|
}
|
|
|
|
if (init_cb(url) != OTA_STATUS_OK)
|
|
{
|
|
LOGE("ota update init failed\n");
|
|
bSucc = RT_FALSE;
|
|
goto ota_err;
|
|
}
|
|
|
|
LOGD("OTA: start loading image...\n");
|
|
debug_size = OTA_UPDATE_DEBUG_UNIT;
|
|
ota_priv.get_size = 0;
|
|
|
|
LOGD("os image max size %u \n", os_size);
|
|
|
|
#ifdef RT_USING_OTA_FROM_HTTP
|
|
ota_start_download_task(NULL);
|
|
#endif
|
|
|
|
while (os_size)
|
|
{
|
|
uint32_t len, readLen;
|
|
len = MINIMUM(os_size, OTA_BUF_SIZE);
|
|
|
|
status = get_cb(ota_buf, len, &readLen, &eof_flag);
|
|
if (status != OTA_STATUS_OK)
|
|
{
|
|
LOGE("status %d\n", status);
|
|
break;
|
|
}
|
|
|
|
rt_memcpy(p_fwbuf, ota_buf, OTA_BUF_SIZE);
|
|
rt_memset(ota_buf, 0, OTA_BUF_SIZE);
|
|
|
|
res = write(test_fd, p_fwbuf, readLen);
|
|
if (res != readLen)
|
|
{
|
|
LOGE("Fw %#d write Error!, size %#d\n", seq, res);
|
|
break;
|
|
}
|
|
|
|
if (!eof_flag)
|
|
{
|
|
os_size -= readLen;
|
|
ota_priv.get_size += readLen;
|
|
}
|
|
else
|
|
{
|
|
ret = OTA_STATUS_OK;
|
|
LOGD("Donwloaded image %u Byte (%u KB) to End \n", ota_priv.get_size,
|
|
ota_priv.get_size / 1024);
|
|
break;
|
|
}
|
|
|
|
if (ota_priv.get_size >= debug_size)
|
|
{
|
|
LOGD("OTA: Donwloaded image (%u KB)...\n",
|
|
ota_priv.get_size / 1024);
|
|
debug_size += OTA_UPDATE_DEBUG_UNIT;
|
|
}
|
|
|
|
rt_thread_delay(10);
|
|
}
|
|
#ifdef RT_USING_OTA_FROM_HTTP
|
|
ota_exit_download_task();
|
|
#endif
|
|
|
|
close(test_fd);
|
|
|
|
ota_err:
|
|
if (ota_buf)
|
|
{
|
|
rt_free_align(ota_buf);
|
|
ota_buf = RT_NULL;
|
|
}
|
|
|
|
if (p_fwbuf)
|
|
{
|
|
rt_free_align(p_fwbuf);
|
|
p_fwbuf = RT_NULL;
|
|
}
|
|
|
|
if (ret != OTA_STATUS_OK)
|
|
{
|
|
if (os_size == 0)
|
|
{
|
|
/* reach max os size, but not end, continue trying to check sections */
|
|
LOGE("download os img size %u == %u, but not end",
|
|
ota_priv.get_size, ota_priv.img_max_size);
|
|
}
|
|
else
|
|
{
|
|
LOGE("Happen some error when downlond...");
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
LOGD("finish loading image %d(0x%#08x)", ota_priv.get_size, ota_priv.get_size);
|
|
|
|
if (bSucc)
|
|
{
|
|
/* do jhash check here before we set slot activity */
|
|
if (ota_verify_img(OTA_VERIFY_JHASH) != OTA_STATUS_OK)
|
|
{
|
|
LOGE("ota check image failed");
|
|
return OTA_STATUS_ERR;
|
|
}
|
|
LOGD("Finish checking os image.\n");
|
|
|
|
/* Verify data partition firmware : flash data partiton with local file*/
|
|
if (ota_data_check(url) != OTA_STATUS_OK)
|
|
{
|
|
LOGE("ota check data image failed");
|
|
return OTA_STATUS_ERR;
|
|
}
|
|
LOGD("Finish checking data image.\n");
|
|
|
|
/* dsp version compare */
|
|
if (ota_priv.data_max_size)
|
|
{
|
|
if (ota_dsp_version_cmp() != OTA_STATUS_OK)
|
|
{
|
|
LOGE("ota dsp version check failed");
|
|
return OTA_STATUS_ERR;
|
|
}
|
|
LOGD("dsp version is accordant!");
|
|
}
|
|
|
|
if (seq == 1) /* pending os Fw 2 slot*/
|
|
LOGD(" ---- Set system Start from FW2 slot----");
|
|
else if (seq == 0) /* pending os Fw 1 slot*/
|
|
LOGD(" ---- Set system Start from FW1 slot----");
|
|
|
|
fw_slot_set_pending(ota_priv.fw_running_slot);
|
|
}
|
|
else
|
|
{
|
|
#ifdef RT_USING_OTA_FROM_HTTP
|
|
ota_exit_download_task();
|
|
#endif
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static ota_status ota_update_image_todo(void *url,
|
|
ota_update_init init_cb,
|
|
ota_update_get get_cb)
|
|
{
|
|
rt_uint8_t seq;
|
|
|
|
seq = ota_get_update_seq();
|
|
if (seq < IMAGE_SEQ_NUM)
|
|
{
|
|
#if OTA_TEST
|
|
return ota_update_image_process_test(seq, url, init_cb, get_cb);
|
|
#else
|
|
return ota_update_image_process(seq, url, init_cb, get_cb);
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
return OTA_STATUS_ERR;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Get the image file with the specified protocol and write to flash
|
|
* @param[in] protocol Pointer to the protocol of getting image file
|
|
* @param[in] url URL of the image file
|
|
* @retval ota_status_t, OTA_STATUS_OK on success
|
|
*/
|
|
ota_status ota_update_image(ota_protocol protocol, void *url)
|
|
{
|
|
if (url == NULL)
|
|
{
|
|
LOGD("url %p\n", url);
|
|
return OTA_STATUS_ERR;
|
|
}
|
|
|
|
switch (protocol)
|
|
{
|
|
#if OTA_OPT_PROTOCOL_FILE
|
|
case OTA_PROTOCOL_FILE:
|
|
return ota_update_image_todo(url, ota_update_file_init, ota_update_file_get);
|
|
#endif
|
|
|
|
#if OTA_OPT_PROTOCOL_HTTP
|
|
case OTA_PROTOCOL_HTTP:
|
|
return ota_update_image_todo(url, ota_update_http_init, ota_update_http_get);
|
|
#endif
|
|
default:
|
|
LOGD("invalid protocol %d\n", protocol);
|
|
return OTA_STATUS_ERR;
|
|
}
|
|
}
|
|
|
|
static ota_status ota_verify_image_none(rt_uint8_t fw_slot)
|
|
{
|
|
return OTA_STATUS_OK;
|
|
}
|
|
|
|
#if OTA_OPT_VERIFY_JHASH
|
|
static ota_status ota_verify_image_hash(rt_uint8_t fw_slot)
|
|
{
|
|
int res = -1;
|
|
|
|
res = fw_CheckHash(fw_slot);
|
|
if (res == 0)
|
|
{
|
|
return OTA_STATUS_OK;
|
|
}
|
|
else
|
|
{
|
|
return OTA_STATUS_ERR;
|
|
}
|
|
}
|
|
#endif /* OTA_OPT_EXTRA_VERIFY_SHA256 */
|
|
|
|
/**
|
|
* @brief Verify the image file
|
|
* @param[in] verify Verification algorithm
|
|
* @param[in] Lun device handle
|
|
* @retval ota_status, OTA_STATUS_OK on success
|
|
*/
|
|
ota_status ota_verify_img(ota_verify verify)
|
|
{
|
|
ota_status status;
|
|
rt_uint8_t seq;
|
|
// image_cfg img_state;
|
|
|
|
seq = ota_get_update_seq();
|
|
if (seq >= IMAGE_SEQ_NUM)
|
|
{
|
|
return OTA_STATUS_ERR;
|
|
}
|
|
|
|
LOGD("%s(), verify slot %d, size 0x%#x", __func__, seq, ota_priv.get_size);
|
|
|
|
#if OTA_IMG_DATA_CORRUPTION_TEST
|
|
{
|
|
int time = 3;
|
|
|
|
LOGD("ota img data corruption test start, pls power down the device");
|
|
while (time)
|
|
{
|
|
rt_thread_delay(1000);
|
|
LOGD("Pls power down the device: %d s", time);
|
|
time--;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
switch (verify)
|
|
{
|
|
case OTA_VERIFY_NONE:
|
|
status = ota_verify_image_none(seq);
|
|
break;
|
|
#if OTA_OPT_VERIFY_JHASH
|
|
case OTA_VERIFY_JHASH:
|
|
status = ota_verify_image_hash(seq);
|
|
break;
|
|
#endif
|
|
default:
|
|
LOGE("invalid verify %d", verify);
|
|
return OTA_STATUS_ERR;
|
|
}
|
|
#if OTA_IMG_DATA_CORRUPTION_TEST
|
|
LOGD("ota img data corruption test end");
|
|
rt_thread_delay(1000);
|
|
#endif
|
|
|
|
if (status != OTA_STATUS_OK)
|
|
{
|
|
LOGE("verify fail, status %d, verify %d", status, verify);
|
|
return OTA_STATUS_ERR;
|
|
}
|
|
|
|
/* Verify fimeware, can do reboot */
|
|
// img_state.seq = seq;
|
|
// img_state.state = IMAGE_STATE_VERIFIED;
|
|
// ota_set_img_state(&img_state);
|
|
|
|
LOGD("OTA: finish checking image.");
|
|
return OTA_STATUS_OK;
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief reboot device
|
|
* @return None
|
|
*/
|
|
void ota_reboot(int system_running)
|
|
{
|
|
LOGD("reboot......\n");
|
|
rt_thread_delay(300);
|
|
|
|
rt_hw_cpu_reset();
|
|
}
|
|
|
|
void ota_main(void *arg)
|
|
{
|
|
char *file_url = NULL;
|
|
ota_status ret;
|
|
uint32_t slot_boot_idx;
|
|
fw_ab_data *ab_data;
|
|
|
|
LOGD("%s Enter...", __func__);
|
|
|
|
#ifdef RT_USING_OTA_FROM_LOCAL
|
|
LOGD("This is ota # LOCAL # update ....");
|
|
/* fw file in emmc device. */
|
|
file_url = rt_malloc(256);
|
|
|
|
if (!file_url)
|
|
{
|
|
LOGD("malloc memory fail ");
|
|
return;
|
|
}
|
|
|
|
/* get current os run seq */
|
|
if (ota_init() != OTA_STATUS_OK)
|
|
goto END;
|
|
|
|
if (fw_slot_get_current_running(&slot_boot_idx) != OTA_STATUS_OK)
|
|
goto END;
|
|
|
|
#ifdef RT_USING_OTA_RECOVERY
|
|
/* if enable recovery mode and running in slot 0, should reboot to slot 1 to
|
|
* run ota task, to do upgrade work.
|
|
*/
|
|
if (slot_boot_idx == 0)
|
|
{
|
|
LOGD("!!! OTA in recovery mode !!!");
|
|
if (file_url)
|
|
rt_free(file_url);
|
|
|
|
if (!fw_slot_change(1 - slot_boot_idx))
|
|
ota_reboot(1 - slot_boot_idx);
|
|
}
|
|
#endif
|
|
|
|
/* according os run seq to get local fw path (url)*/
|
|
rt_memset(file_url, 0, 256);
|
|
rt_memcpy(file_url, OTA_FW_LOCAL_PATH, rt_strlen(OTA_FW_LOCAL_PATH));
|
|
|
|
fw_slot_reset_flag(slot_boot_idx);
|
|
|
|
ret = ota_update_image(OTA_PROTOCOL_FILE, file_url);
|
|
if (OTA_STATUS_OK == ret)
|
|
{
|
|
if (file_url)
|
|
rt_free(file_url);
|
|
|
|
//if (!fw_slot_change(1 - slot_boot_idx))
|
|
ota_reboot(1 - slot_boot_idx);
|
|
}
|
|
else
|
|
{
|
|
LOGE("ota update image Fail!!!\n");
|
|
goto END;
|
|
}
|
|
|
|
#elif (defined RT_USING_OTA_FROM_HTTP)
|
|
LOGD("This is ota http update ....");
|
|
|
|
file_url = rt_malloc(256);
|
|
|
|
if (!file_url)
|
|
{
|
|
LOGD("malloc memory fail ");
|
|
return;
|
|
}
|
|
|
|
rt_memset(file_url, 0, 256);
|
|
|
|
/* get current fw run slot */
|
|
if (ota_init() != OTA_STATUS_OK)
|
|
goto END;
|
|
|
|
if (fw_slot_get_current_running(&slot_boot_idx) != OTA_STATUS_OK)
|
|
goto END;
|
|
|
|
/* according fw run slot to get fw position in one firmare url file*/
|
|
rt_memcpy(file_url, RT_OTA_HTTP_URL, rt_strlen(RT_OTA_HTTP_URL));
|
|
|
|
ret = ota_update_image(OTA_PROTOCOL_HTTP, file_url);
|
|
if (OTA_STATUS_OK == ret)
|
|
{
|
|
LOGD("Fw have wrote flash Success!!!.\n");
|
|
if (file_url)
|
|
rt_free(file_url);
|
|
|
|
ota_reboot(1 - slot_boot_idx);
|
|
}
|
|
else
|
|
LOGE("ota update image Fail!!!\n");
|
|
|
|
#endif
|
|
|
|
END:
|
|
LOGE(">>>>>>>> EXIT ota main");
|
|
if (file_url)
|
|
rt_free(file_url);
|
|
|
|
if (slot_boot_idx == 1)
|
|
{
|
|
/* fw A never boot success and not found firmware to update ,
|
|
we switch boot to maskrom
|
|
*/
|
|
ab_data = fw_ab_data_get();
|
|
if (ab_data->slots[0].successful_boot == 0
|
|
&& ab_data->slots[0].tries_remaining == 0)
|
|
{
|
|
LOGE("###### Fw A boot never Success,will boot to maskrom! ######\n");
|
|
BSP_SetLoaderFlag();
|
|
ota_reboot(0);
|
|
}
|
|
}
|
|
}
|
|
|
|
rt_thread_t ota_task_start(void)
|
|
{
|
|
LOGD("%s\n", __func__);
|
|
rt_thread_t ota_task_thread;
|
|
ota_task_thread = rt_thread_create("ota_task",
|
|
ota_main,
|
|
RT_NULL,
|
|
8192 * 2,
|
|
15,
|
|
20);
|
|
|
|
if (!ota_task_thread)
|
|
{
|
|
LOGD("ota task create failed");
|
|
return NULL;
|
|
}
|
|
else
|
|
rt_thread_startup(ota_task_thread);
|
|
|
|
return ota_task_thread;
|
|
}
|
|
|
|
void ota_task_exit(rt_thread_t h_vt)
|
|
{
|
|
RT_ASSERT(h_vt != NULL);
|
|
rt_thread_delete(h_vt);
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/*
|
|
* Below code just for aging test
|
|
*/
|
|
void ota_test_task(void *arg)
|
|
{
|
|
char *file_url = NULL;
|
|
ota_status ret;
|
|
uint32_t slot_boot_idx;
|
|
|
|
LOGD("%s Enter...", __func__);
|
|
|
|
#ifdef RT_USING_OTA_FROM_LOCAL
|
|
LOGD("This is ota # LOCAL # test ....");
|
|
/* fw file in emmc device. */
|
|
file_url = rt_calloc(1, 256);
|
|
if (!file_url)
|
|
{
|
|
LOGD("malloc memory fail ");
|
|
return;
|
|
}
|
|
|
|
/* get current os run seq */
|
|
if (ota_init() != OTA_STATUS_OK)
|
|
goto END;
|
|
|
|
if (fw_slot_get_current_running(&slot_boot_idx) != OTA_STATUS_OK)
|
|
goto END;
|
|
|
|
/* according os run seq to get local fw path (url)*/
|
|
rt_memcpy(file_url, OTA_FW_LOCAL_PATH, rt_strlen(OTA_FW_LOCAL_PATH));
|
|
|
|
fw_slot_reset_flag(slot_boot_idx);
|
|
ret = ota_update_image(OTA_PROTOCOL_FILE, file_url);
|
|
if (OTA_STATUS_OK != ret)
|
|
{
|
|
LOGE("ota update image Fail!!!\n");
|
|
goto END;
|
|
}
|
|
|
|
#ifdef RT_USING_OTA_RECOVERY
|
|
/* if enable recovery mode and running in slot 0, should reboot to slot 1 to
|
|
* run ota task, to do upgrade work.
|
|
*/
|
|
if (slot_boot_idx == 0 && OTA_STATUS_OK == ret)
|
|
{
|
|
LOGD("!!! OTA type is recovery mode, will reboot to run Fw2 !!!");
|
|
if (file_url)
|
|
rt_free(file_url);
|
|
|
|
if (!fw_slot_change(1 - slot_boot_idx))
|
|
ota_reboot(1 - slot_boot_idx);
|
|
}
|
|
#endif //#ifdef RT_USING_OTA_RECOVERY
|
|
|
|
#endif //#ifdef RT_USING_OTA_FROM_LOCAL
|
|
|
|
END:
|
|
if (file_url)
|
|
rt_free(file_url);
|
|
}
|
|
|
|
|
|
void ota_test_loop()
|
|
{
|
|
LOGD("%s\n", __func__);
|
|
rt_thread_t ota_task_thread;
|
|
ota_task_thread = rt_thread_create("ota_test_task",
|
|
ota_test_task,
|
|
RT_NULL,
|
|
8192 * 2,
|
|
15,
|
|
20);
|
|
|
|
if (!ota_task_thread)
|
|
{
|
|
LOGD("ota test task create failed");
|
|
return;
|
|
}
|
|
else
|
|
rt_thread_startup(ota_task_thread);
|
|
}
|
|
|
|
#endif
|
|
|