1950 lines
49 KiB
C
1950 lines
49 KiB
C
/****************************************************************************
|
|
|
|
Copyright(c) 2019 by Aerospace C.Power (Chongqing) Microelectronics. ALL RIGHTS RESERVED.
|
|
|
|
This Information is proprietary to Aerospace C.Power (Chongqing) Microelectronics and MAY NOT
|
|
be copied by any method or incorporated into another program without
|
|
the express written consent of Aerospace C.Power. This Information or any portion
|
|
thereof remains the property of Aerospace C.Power. The Information contained herein
|
|
is believed to be accurate and Aerospace C.Power assumes no responsibility or
|
|
liability for its use in any way and conveys no license or title under
|
|
any patent or copyright and makes no representation or warranty that this
|
|
Information is free from patent or copyright infringement.
|
|
|
|
****************************************************************************/
|
|
#include "os_types.h"
|
|
#include "os_mem.h"
|
|
#include "os_lock.h"
|
|
#include "os_task.h"
|
|
|
|
#include "cpu.h"
|
|
#include "gp_timer.h"
|
|
|
|
#include "flash.h"
|
|
#include "iot_config.h"
|
|
#include "iot_module.h"
|
|
#include "iot_io.h"
|
|
#include "iot_string.h"
|
|
#include "iot_system.h"
|
|
#include "iot_img_hdr.h"
|
|
#include "iot_board.h"
|
|
#include "iot_pib.h"
|
|
#include "iot_dbglog_parser.h"
|
|
#include "iot_flash_layout.h"
|
|
|
|
#include "iot_pkt_api.h"
|
|
#include "os_task_api.h"
|
|
#include "iot_flash_api.h"
|
|
#include "iot_crc_api.h"
|
|
#include "iot_utils_api.h"
|
|
#include "iot_errno_api.h"
|
|
#include "iot_wdg_api.h"
|
|
#include "iot_dbglog_api.h"
|
|
|
|
#include "mtd.h"
|
|
|
|
#define MTD_CRC_CALC_LEN (64)
|
|
#define MTD_COPY_FLASH_SIZE_ONCE (512)
|
|
|
|
typedef struct _mtd_device_t {
|
|
uint32_t device_id; /* flash device id */
|
|
uint32_t pagesize; /* flash page size */
|
|
uint32_t sectorsize; /* flash sector size */
|
|
uint32_t blocksize; /* flash block size */
|
|
uint32_t size; /* flash memory size */
|
|
} mtd_device_t;
|
|
|
|
typedef struct _mtd_info_t {
|
|
/* page erase command enable */
|
|
uint8_t page_erase_ena;
|
|
uint8_t resv[3];
|
|
/* pointer of flash chip information struction */
|
|
mtd_device_t dev;
|
|
/* pointer of partition information struction */
|
|
part_info_t *part;
|
|
/* file system information struction */
|
|
struct {
|
|
int fd;
|
|
uint32_t pos;
|
|
int used;
|
|
} file[PART_NUM_MAX];
|
|
/* operation functions struction */
|
|
struct {
|
|
uint8_t (*init)(int mode);
|
|
uint8_t (*read)(void* data, uint32_t addr, int size, uint8_t mode);
|
|
uint8_t (*write)(const void* data, uint32_t addr, uint32_t size,
|
|
void *param);
|
|
uint8_t (*erase)(uint32_t addr, void *param);
|
|
uint8_t (*get_dev_id)(void *data);
|
|
uint8_t (*addr_mapping)(uint32_t offset1, uint32_t offset2,
|
|
uint32_t size);
|
|
} opt;
|
|
} mtd_info_t;
|
|
|
|
/* mtd boot parameter information */
|
|
static uint8_t g_first_boot = 0;
|
|
static uint8_t g_start_flag = 0;
|
|
static uint8_t g_last_flag = 0;
|
|
static uint8_t g_cnt_flag = 0;
|
|
bool_t g_upgrade_flag = false;
|
|
/* Indicates whether this startup is the first after burning. */
|
|
uint8_t g_first_run = 0;
|
|
|
|
os_mutex_h mtd_op_mutex = NULL;
|
|
flash_os_cb_t g_flash_os_cb = {0};
|
|
|
|
/* mtd partion information */
|
|
uint8_t g_dev_flash_size = FLASH_1M;
|
|
uint8_t g_run_in_psram = 0;
|
|
uint8_t g_part_num_fw1 = PART_NUM_FW1;
|
|
uint8_t g_part_num_fw2 = PART_NUM_FW2;
|
|
/* partition array */
|
|
part_info_t g_part_info[PART_NUM_MAX] = {0};
|
|
/* mtd information */
|
|
mtd_info_t g_mtd_info = {0};
|
|
|
|
/* flash chip informations */
|
|
const mtd_device_t mtd_flash_devices[] = {
|
|
/* device_id, pagesize, sectorsize, blocksize, size */
|
|
{FLASH_VENDOR_ID_GD, 0x100, 0x1000, 0x10000, 0x3FFFFF},/* model: gd25q32c */
|
|
{FLASH_VENDOR_ID_PUYA, 0x100, 0x1000, 0x10000, 0x3FFFFF},/* model: p25q80h */
|
|
{FLASH_VENDOR_ID_WINBOND, 0x100, 0x1000, 0x10000, 0x3FFFFF},/* model: p25q80h */
|
|
{0x0002, 0x100, 0x1000, 0x10000, 0x3FFFFF}
|
|
};
|
|
|
|
extern uint32_t g_fw_mode;
|
|
|
|
extern void vTaskSuspendAll();
|
|
extern void xTaskResumeAll();
|
|
extern uint32_t patch_puya_twicewrite_flag_check(void);
|
|
|
|
int32_t mtd_patch_for_puya(void);
|
|
|
|
/**************************** mtd init functions ******************************/
|
|
void mtd_os_cb_enable()
|
|
{
|
|
g_flash_os_cb.get_gp_timer_val = gp_timer_get_current_val;
|
|
g_flash_os_cb.task_suspend_all = vTaskSuspendAll;
|
|
g_flash_os_cb.task_resume_all = xTaskResumeAll;
|
|
}
|
|
|
|
void mtd_set_flash_size(uint8_t size)
|
|
{
|
|
if (size == 1)
|
|
g_dev_flash_size = FLASH_1M;
|
|
else if(size == 2)
|
|
g_dev_flash_size = FLASH_2M;
|
|
else if(size >= 3)
|
|
g_dev_flash_size = FLASH_4M;
|
|
else /*compatable with old sbl*/
|
|
g_dev_flash_size = FLASH_1M;
|
|
}
|
|
|
|
uint32_t mtd_get_flash_size()
|
|
{
|
|
return g_dev_flash_size;
|
|
}
|
|
|
|
uint8_t mtd_get_psram_state()
|
|
{
|
|
return g_run_in_psram;
|
|
}
|
|
|
|
void mtd_set_psram_state(uint8_t en)
|
|
{
|
|
g_run_in_psram = en;
|
|
}
|
|
|
|
uint32_t mtd_flash_init(int index, int mode)
|
|
{
|
|
int i = 0;
|
|
part_info_t *part_info = g_part_info;
|
|
|
|
iot_layout_init_index(FLASH_LAYOUT_INDEX, g_dev_flash_size, g_run_in_psram);
|
|
|
|
/* init local partition array */
|
|
for (i = 0; i < PART_NUM_MAX; i++) {
|
|
part_info_t part_info_temp;
|
|
if (iot_layout_get_part_info(i, &part_info_temp) != ERR_OK) {
|
|
continue;
|
|
}
|
|
part_info[i].offset = part_info_temp.offset;
|
|
part_info[i].size = part_info_temp.size;
|
|
part_info[i].authority = part_info_temp.authority;
|
|
}
|
|
|
|
/* set partition variable value */
|
|
#if (BUILD_AMP_TYPE == IOT_BUILD_AMP_CUSTOM)
|
|
g_part_num_fw1 = PART_NUM_CUS_FW1;
|
|
g_part_num_fw2 = PART_NUM_CUS_FW2;
|
|
#else
|
|
g_part_num_fw1 = PART_NUM_FW1;
|
|
g_part_num_fw2 = PART_NUM_FW2;
|
|
#endif
|
|
|
|
/* flash firmware need to re-define log partition to the back of run partition */
|
|
if (g_dev_flash_size > FLASH_1M && !g_run_in_psram) {
|
|
uint32_t temp_fw_size, temp_run_offset, temp_run_size, temp_log_size;
|
|
temp_fw_size = (uint32_t)&_flash_end - (uint32_t)&_start; //fw size
|
|
// padding 4K byte to avoid overlap
|
|
temp_fw_size += 0x1000;
|
|
// 4K aligned
|
|
temp_fw_size += 0x1000;
|
|
temp_fw_size &= ~0xFFF;
|
|
#if (BUILD_AMP_TYPE == IOT_BUILD_AMP_CUSTOM)
|
|
temp_run_offset = part_info[PART_NUM_CUS_RUN].offset;
|
|
temp_run_size = part_info[PART_NUM_CUS_RUN].size;
|
|
#else
|
|
temp_run_offset = part_info[PART_NUM_RUN].offset;
|
|
temp_run_size = part_info[PART_NUM_RUN].size;
|
|
#endif
|
|
temp_log_size = (temp_run_size - temp_fw_size) >> 1; //divide by 2
|
|
part_info[PART_NUM_LOG1].offset = temp_run_offset + temp_fw_size;
|
|
part_info[PART_NUM_LOG1].size = temp_log_size;
|
|
part_info[PART_NUM_LOG2].offset =
|
|
temp_run_offset + temp_fw_size + temp_log_size;
|
|
part_info[PART_NUM_LOG2].size = temp_log_size;
|
|
}
|
|
|
|
/* mtd params init */
|
|
os_mem_cpy(&g_mtd_info.dev, &mtd_flash_devices[index], sizeof(mtd_device_t));
|
|
g_mtd_info.part = part_info;
|
|
if (mtd_flash_devices[index].device_id == FLASH_VENDOR_ID_PUYA) {
|
|
g_mtd_info.page_erase_ena = MODE_ERASE_PAGE;
|
|
} else {
|
|
g_mtd_info.page_erase_ena = MODE_ERASE_SECTOR;
|
|
}
|
|
|
|
/* mtd callback functions */
|
|
g_mtd_info.opt.init = flash_init;
|
|
g_mtd_info.opt.read = flash_read;
|
|
g_mtd_info.opt.write = flash_write;
|
|
g_mtd_info.opt.erase = flash_erase;
|
|
g_mtd_info.opt.get_dev_id = flash_get_dev_id;
|
|
|
|
/* init file system */
|
|
for (i = 0; i < PART_NUM_MAX; i++) {
|
|
g_mtd_info.file[i].used = FILE_UNUSE;
|
|
g_mtd_info.file[i].fd = i;
|
|
g_mtd_info.file[i].pos = 0;
|
|
}
|
|
|
|
mtd_os_cb_enable();
|
|
g_mtd_info.opt.init(mode);
|
|
|
|
if (mtd_op_mutex == NULL) {
|
|
mtd_op_mutex = os_create_mutex(IOT_DRIVER_MID);
|
|
}
|
|
|
|
return HAL_OK;
|
|
}
|
|
|
|
int mtd_device_probe(void)
|
|
{
|
|
/* get current flash device id */
|
|
int i = 0;
|
|
uint32_t id = 0;
|
|
|
|
flash_probe(&id);
|
|
|
|
for (i = 0; IOT_ARRAY_CNT(mtd_flash_devices); i++) {
|
|
if (mtd_flash_devices[i].device_id == id) {
|
|
return i;
|
|
}
|
|
}
|
|
|
|
/* probe fail */
|
|
return -1;
|
|
}
|
|
|
|
uint32_t mtd_device_init(int mode)
|
|
{
|
|
int index;
|
|
|
|
index = mtd_device_probe();
|
|
if (index < 0) {
|
|
return HAL_ERROR;
|
|
}
|
|
|
|
mtd_flash_init(index, mode);
|
|
|
|
#if FLASH_HIGH_FREQ_ENABLE
|
|
flash_clk_div_set(0);
|
|
#else
|
|
flash_clk_div_set(1);
|
|
#endif
|
|
|
|
mtd_patch_for_puya();
|
|
|
|
return HAL_OK;
|
|
}
|
|
|
|
int mtd_device_get_info(void* buf, uint32_t type)
|
|
{
|
|
uint8_t* p = (uint8_t*)buf;
|
|
(void)type;
|
|
|
|
if (g_mtd_info.opt.get_dev_id) {
|
|
g_mtd_info.opt.get_dev_id(p);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int mtd_get_size_of_erase_once(int fd)
|
|
{
|
|
if (fd > PART_NUM_MAX) {
|
|
return 0;
|
|
}
|
|
|
|
if (g_mtd_info.page_erase_ena == MODE_ERASE_PAGE) {
|
|
return PAGE_PROGRAM_SIZE;
|
|
} else {
|
|
return SECTOR_ERASE_SIZE;
|
|
}
|
|
}
|
|
|
|
/************************* partition basics functions *************************/
|
|
uint32_t dev_get_oem_part_num(uint8_t * num)
|
|
{
|
|
*num = PART_NUM_OEM;
|
|
return HAL_OK;
|
|
}
|
|
|
|
uint32_t dev_get_cal_data_part_num(uint8_t * num)
|
|
{
|
|
*num = PART_NUM_CAL_DATA;
|
|
return HAL_OK;
|
|
}
|
|
|
|
uint32_t dev_get_boot_fw_part_num(uint8_t *part)
|
|
{
|
|
if (g_start_flag == 0) {
|
|
*part = g_part_num_fw1;
|
|
} else if (g_start_flag == 1) {
|
|
*part = g_part_num_fw2;
|
|
} else {
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
uint32_t dev_get_boot_pib_part_num(uint8_t *part)
|
|
{
|
|
if (g_last_flag == 0) {
|
|
*part = PART_NUM_PIB1;
|
|
} else if (g_last_flag == 1) {
|
|
*part = PART_NUM_PIB2;
|
|
} else {
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
uint32_t dev_get_boot_cus_part_num(uint8_t *part)
|
|
{
|
|
*part = PART_NUM_INVALID;
|
|
|
|
if (g_part_info[PART_NUM_CUS_FW1].size == 0 ||
|
|
g_part_info[PART_NUM_CUS_FW2].size == 0) {
|
|
return 1;
|
|
}
|
|
|
|
if (g_last_flag == 0) {
|
|
*part = PART_NUM_CUS_FW1;
|
|
} else if (g_last_flag == 1) {
|
|
*part = PART_NUM_CUS_FW2;
|
|
} else {
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
uint32_t dev_get_upgrade_fw_part_num(uint8_t *part)
|
|
{
|
|
uint32_t start_part = 0;
|
|
|
|
/* g_start_flag cann't used at here, because an exception may occur
|
|
* before it is initialized.
|
|
*/
|
|
if (dev_param_get_start_flag(&start_part)) {
|
|
return 1;
|
|
}
|
|
|
|
if (start_part == 0) {
|
|
*part = g_part_num_fw2;
|
|
} else if (start_part == 1) {
|
|
*part = g_part_num_fw1;
|
|
} else {
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
uint32_t dev_get_upgrade_pib_part_num(uint8_t *part)
|
|
{
|
|
if (g_last_flag == 0) {
|
|
*part = PART_NUM_PIB2;
|
|
} else if (g_last_flag == 1) {
|
|
*part = PART_NUM_PIB1;
|
|
} else {
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
uint32_t dev_get_upgrade_cus_part_num(uint8_t *part)
|
|
{
|
|
*part = PART_NUM_INVALID;
|
|
|
|
if (g_part_info[PART_NUM_CUS_FW1].size == 0 ||
|
|
g_part_info[PART_NUM_CUS_FW2].size == 0) {
|
|
return 1;
|
|
}
|
|
|
|
if (g_last_flag == 0) {
|
|
*part = PART_NUM_CUS_FW2;
|
|
} else if (g_last_flag == 1) {
|
|
*part = PART_NUM_CUS_FW1;
|
|
} else {
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
uint8_t dev_get_pib_ext_part_num(uint8_t part)
|
|
{
|
|
if (part == PART_NUM_PIB1) {
|
|
return PART_NUM_PIB1_EXT;
|
|
} else {
|
|
return PART_NUM_PIB2_EXT;
|
|
}
|
|
}
|
|
|
|
uint32_t dev_get_part_size(uint8_t part)
|
|
{
|
|
return g_part_info[part].size;
|
|
}
|
|
|
|
/************************ file system basics functions ************************/
|
|
int dev_open(int num, uint32_t flags)
|
|
{
|
|
int fd;
|
|
uint32_t core_id;
|
|
|
|
if (num < PART_NUM_MIN || num >= PART_NUM_MAX) {
|
|
return -1;
|
|
}
|
|
|
|
fd = g_mtd_info.file[num].fd;
|
|
|
|
core_id = cpu_get_mhartid();
|
|
if (!(MTD_AUTH_RW & GET_CORE_AUTHORITY(g_mtd_info.part[num].authority,
|
|
core_id))) {
|
|
return -1;
|
|
}
|
|
|
|
if ((!os_atomic_check_set(&g_mtd_info.file[num].used, FILE_UNUSE,
|
|
FILE_INUSE)) && flags == 0) {
|
|
/* re-open */
|
|
return -1;
|
|
}
|
|
|
|
g_mtd_info.file[num].pos = 0;
|
|
|
|
return fd;
|
|
}
|
|
|
|
int dev_close(int fd)
|
|
{
|
|
if (fd < 0) {
|
|
/* fd invalid */
|
|
return -1;
|
|
}
|
|
|
|
if (!os_atomic_check_set(&g_mtd_info.file[fd].used, FILE_INUSE,
|
|
FILE_UNUSE)) {
|
|
return -1;
|
|
}
|
|
g_mtd_info.file[fd].pos = 0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int dev_seek(int fd, uint32_t offset, uint8_t fromwhere)
|
|
{
|
|
uint32_t pos = 0;
|
|
uint32_t part_size = 0;
|
|
|
|
if (fd < 0 || g_mtd_info.file[fd].used != FILE_INUSE) {
|
|
/* fd invalid */
|
|
return -1;
|
|
}
|
|
|
|
pos = g_mtd_info.file[fd].pos;
|
|
part_size = g_mtd_info.part[fd].size;
|
|
|
|
if (offset >= part_size) {
|
|
/* over range */
|
|
return -1;
|
|
}
|
|
|
|
switch(fromwhere) {
|
|
case DEV_SEEK_SET:
|
|
g_mtd_info.file[fd].pos = offset;
|
|
break;
|
|
case DEV_SEEK_CUR:
|
|
if(pos + offset > part_size){
|
|
/* over range */
|
|
return -1;
|
|
}
|
|
g_mtd_info.file[fd].pos = pos + offset;
|
|
break;
|
|
case DEV_SEEK_END:
|
|
g_mtd_info.file[fd].pos = g_mtd_info.part[fd].size - offset;
|
|
break;
|
|
}
|
|
|
|
return g_mtd_info.file[fd].pos;
|
|
}
|
|
|
|
int dev_read(int fd, void* buf, size_t count)
|
|
{
|
|
int ret = 0;
|
|
uint32_t core_id;
|
|
uint32_t pos, offset, part_size, addr;
|
|
uint8_t* p = (uint8_t*)buf;
|
|
|
|
if (fd < 0 || (g_mtd_info.file[fd].used != FILE_INUSE)) {
|
|
/* fd invalid */
|
|
return -1;
|
|
}
|
|
|
|
core_id = cpu_get_mhartid();
|
|
if (!(MTD_AUTH_READ & GET_CORE_AUTHORITY(g_mtd_info.part[fd].authority,
|
|
core_id))) {
|
|
return -1;
|
|
}
|
|
|
|
pos = g_mtd_info.file[fd].pos;
|
|
offset = g_mtd_info.part[fd].offset;
|
|
part_size = g_mtd_info.part[fd].size;
|
|
addr = offset + pos;
|
|
|
|
if(pos + count > part_size) {
|
|
/* over range */
|
|
return -1;
|
|
}
|
|
|
|
if (FLASH_OS_ENABLE == flash_os_is_enable()) {
|
|
os_acquire_mutex(mtd_op_mutex);
|
|
}
|
|
ret = g_mtd_info.opt.read(p, addr, count, MOD_SFC_READ_QUAD_FAST);
|
|
if (ret != HAL_OK) {
|
|
if (FLASH_OS_ENABLE == flash_os_is_enable()) {
|
|
os_release_mutex(mtd_op_mutex);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/* position move */
|
|
pos += count;
|
|
g_mtd_info.file[fd].pos = pos;
|
|
|
|
if (FLASH_OS_ENABLE == flash_os_is_enable()) {
|
|
os_release_mutex(mtd_op_mutex);
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
int dev_write(int fd, void*buf, size_t count)
|
|
{
|
|
uint8_t is_erase;
|
|
if ((fd == g_part_num_fw1) || (fd == g_part_num_fw2)) {
|
|
/* using this, please make sure the part has been erased */
|
|
is_erase = 0;
|
|
} else {
|
|
is_erase = 1;
|
|
}
|
|
|
|
return dev_write_ext(fd, buf, count, is_erase);
|
|
}
|
|
|
|
int dev_write_ext(int fd, void *buf, size_t count, uint8_t is_erase)
|
|
{
|
|
int ret = 0;
|
|
uint8_t* p = (uint8_t*)buf;
|
|
uint32_t core_id;
|
|
uint32_t pos, offset, part_size, addr;
|
|
flash_write_param_t param = {0};
|
|
|
|
if (fd < 0) {
|
|
/* fd invalid */
|
|
return -1;
|
|
}
|
|
|
|
if ((FLASH_OS_ENABLE == flash_os_is_enable()) && (g_mtd_info.file[fd].used !=
|
|
FILE_INUSE)) {
|
|
return -1;
|
|
}
|
|
|
|
core_id = cpu_get_mhartid();
|
|
if (!(MTD_AUTH_WRITE & GET_CORE_AUTHORITY(g_mtd_info.part[fd].authority,
|
|
core_id))) {
|
|
return -1;
|
|
}
|
|
|
|
pos = g_mtd_info.file[fd].pos;
|
|
offset = g_mtd_info.part[fd].offset;
|
|
part_size = g_mtd_info.part[fd].size;
|
|
addr = offset + pos;
|
|
|
|
if(pos + count > part_size) {
|
|
/* over range */
|
|
return -1;
|
|
}
|
|
|
|
if (FLASH_OS_ENABLE == flash_os_is_enable()) {
|
|
os_acquire_mutex(mtd_op_mutex);
|
|
}
|
|
|
|
param.read_mode = MOD_SFC_READ_QUAD_IO_FAST;
|
|
param.write_mode = MOD_SFC_PROG_QUAD;
|
|
param.erase_mode = g_mtd_info.page_erase_ena;
|
|
|
|
if (FLASH_OS_ENABLE == flash_os_is_enable()) {
|
|
param.sw_mode = flash_get_pe_mode();
|
|
if(param.sw_mode == MOD_SW_MODE_ENA){
|
|
param.cb = &g_flash_os_cb;
|
|
} else {
|
|
param.cb = 0;
|
|
}
|
|
} else {
|
|
param.sw_mode = MOD_SW_MODE_DIS;
|
|
param.cb = 0;
|
|
}
|
|
|
|
param.is_erase = !!is_erase;
|
|
|
|
iot_printf("[dev_write] addr: %08x, count: %08x is_erase %d\n", addr, count,
|
|
param.is_erase);
|
|
ret = g_mtd_info.opt.write( p, addr, count, ¶m);
|
|
if (ret != HAL_OK) {
|
|
goto w_err;
|
|
}
|
|
|
|
iot_printf("[dev_write] finished, addr:%08x, count:%08x\n", addr, count);
|
|
/* position move */
|
|
pos += count;
|
|
g_mtd_info.file[fd].pos = pos;
|
|
if (FLASH_OS_ENABLE == flash_os_is_enable()) {
|
|
os_release_mutex(mtd_op_mutex);
|
|
}
|
|
return count;
|
|
|
|
w_err:
|
|
if (FLASH_OS_ENABLE == flash_os_is_enable()) {
|
|
os_release_mutex(mtd_op_mutex);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
int dev_erase(int fd, uint32_t addr, uint8_t mode)
|
|
{
|
|
uint8_t ret = 0;
|
|
uint32_t offset = 0;
|
|
uint32_t size = 0;
|
|
uint32_t pos = 0;
|
|
uint32_t core_id;
|
|
flash_write_param_t param = {0};
|
|
|
|
if (fd < 0) {
|
|
/* fd invalid */
|
|
return -1;
|
|
}
|
|
|
|
if ((FLASH_OS_ENABLE == flash_os_is_enable()) && (g_mtd_info.file[fd].used !=
|
|
FILE_INUSE)) {
|
|
return -1;
|
|
}
|
|
|
|
core_id = cpu_get_mhartid();
|
|
if (!(MTD_AUTH_WRITE & GET_CORE_AUTHORITY(g_mtd_info.part[fd].authority,
|
|
core_id))) {
|
|
return -1;
|
|
}
|
|
|
|
if (addr > g_mtd_info.part[fd].size) {
|
|
return -1;
|
|
}
|
|
|
|
if (FLASH_OS_ENABLE == flash_os_is_enable()) {
|
|
os_acquire_mutex(mtd_op_mutex);
|
|
}
|
|
|
|
offset = g_mtd_info.part[fd].offset;
|
|
size = g_mtd_info.part[fd].size;
|
|
|
|
if (FLASH_OS_ENABLE == flash_os_is_enable()) {
|
|
param.sw_mode = flash_get_pe_mode();
|
|
if(param.sw_mode == MOD_SW_MODE_ENA){
|
|
param.cb = &g_flash_os_cb;
|
|
} else {
|
|
param.cb = 0;
|
|
}
|
|
} else {
|
|
param.sw_mode = MOD_SW_MODE_DIS;
|
|
param.cb = 0;
|
|
}
|
|
|
|
if (mode == DEV_ERASE_TYPE_FULL_PART) {
|
|
pos = offset;
|
|
while(size > 0) {
|
|
if (size >= BLOCK_ERASE_64K_SIZE) {
|
|
param.erase_mode = MODE_ERASE_BLOCK64;
|
|
ret = g_mtd_info.opt.erase(pos, ¶m);
|
|
if (ret > 0) {
|
|
goto e_err;
|
|
}
|
|
size -= BLOCK_ERASE_64K_SIZE;
|
|
pos += BLOCK_ERASE_64K_SIZE;
|
|
} else if (size >= SECTOR_ERASE_SIZE) {
|
|
param.erase_mode = MODE_ERASE_SECTOR;
|
|
ret = g_mtd_info.opt.erase(pos, ¶m);
|
|
if (ret > 0) {
|
|
goto e_err;
|
|
}
|
|
size -= SECTOR_ERASE_SIZE;
|
|
pos += SECTOR_ERASE_SIZE;
|
|
} else {
|
|
goto e_err;
|
|
}
|
|
}
|
|
} else if (mode == DEV_ERASE_TYPE_SECTOR) {
|
|
param.erase_mode = MODE_ERASE_SECTOR;
|
|
ret = g_mtd_info.opt.erase(offset + addr, ¶m);
|
|
if (ret > 0) {
|
|
goto e_err;
|
|
}
|
|
} else if (mode == DEV_ERASE_TYPE_PAGE) {
|
|
param.erase_mode = MODE_ERASE_PAGE;
|
|
ret = g_mtd_info.opt.erase(offset + addr, ¶m);
|
|
if (ret > 0) {
|
|
goto e_err;
|
|
}
|
|
} else {
|
|
goto e_err;
|
|
}
|
|
|
|
if (FLASH_OS_ENABLE == flash_os_is_enable()) {
|
|
os_release_mutex(mtd_op_mutex);
|
|
}
|
|
return 0;
|
|
|
|
e_err:
|
|
if (FLASH_OS_ENABLE == flash_os_is_enable()) {
|
|
os_release_mutex(mtd_op_mutex);
|
|
IOT_ASSERT(0);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/************************ image header basics functions ***********************/
|
|
/**
|
|
* @brief mtd_get_hdr(): get firmware header information of specified partition.
|
|
* @param part_num: the specified partition.
|
|
* @param hdr: pointer to save header information.
|
|
* @return ERR_FAIL: failed; ERR_OK: succeed.
|
|
*/
|
|
static uint32_t mtd_get_hdr(uint8_t part_num, imgHdr *hdr)
|
|
{
|
|
int fd;
|
|
static uint8_t last_part = PART_NUM_INVALID;
|
|
static uint8_t block[HEADER_TOLTAL_SIZE];
|
|
|
|
if (part_num >= PART_NUM_MAX) {
|
|
return ERR_FAIL;
|
|
}
|
|
os_mem_set(hdr, 0, sizeof(hdr));
|
|
|
|
if (part_num != last_part) {
|
|
os_mem_set(block, 0, sizeof(block));
|
|
fd = dev_open(part_num, 0);
|
|
if (fd > 0) {
|
|
dev_read(fd, block, HEADER_TOLTAL_SIZE);
|
|
dev_close(fd);
|
|
} else {
|
|
return ERR_FAIL;
|
|
}
|
|
}
|
|
|
|
img_header_construct(hdr, (char *)block);
|
|
if (iot_imghdr_get_guard(hdr) != IMAGE_GUARD) {
|
|
/* header information is invalid */
|
|
last_part = PART_NUM_INVALID;
|
|
return ERR_FAIL;
|
|
}
|
|
last_part = part_num;
|
|
|
|
return ERR_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief mtd_get_hdr_img_size(): get image size of specified partition from hdr.
|
|
* @param part: the specified partition.
|
|
* @return 0: failed; other: image size.
|
|
*/
|
|
uint32_t mtd_get_hdr_img_size(uint8_t part)
|
|
{
|
|
imgHdr hdr = {0};
|
|
|
|
if (mtd_get_hdr(part, &hdr) != ERR_OK) {
|
|
return 0;
|
|
}
|
|
|
|
return iot_imghdr_get_imgSize(&hdr);
|
|
}
|
|
|
|
/**
|
|
* @brief mtd_get_hdr_fw_size(): get firmware size of specified partition from hdr.
|
|
* only v0\v0.1 header struction has fw_size member, and sbl\oem\pib fixed 0.
|
|
* @param part: the specified partition.
|
|
* @return 0: failed; other: firmware size.
|
|
*/
|
|
uint32_t mtd_get_hdr_fw_size(uint8_t part)
|
|
{
|
|
imgHdr hdr = {0};
|
|
|
|
if (mtd_get_hdr(part, &hdr) != ERR_OK) {
|
|
return 0;
|
|
}
|
|
|
|
return iot_imghdr_get_fwSize(&hdr);
|
|
}
|
|
|
|
/**
|
|
* @brief mtd_get_hdr_img_crc(): get crc of specified partition from hdr.
|
|
* @param part: the specified partition.
|
|
* @return 0: failed; other: firmware size.
|
|
*/
|
|
uint32_t mtd_get_hdr_img_crc(uint8_t part)
|
|
{
|
|
imgHdr hdr = {0};
|
|
|
|
if (mtd_get_hdr(part, &hdr) != ERR_OK) {
|
|
return 0;
|
|
}
|
|
|
|
return iot_imghdr_get_imgCRC(&hdr);
|
|
}
|
|
|
|
/********************** boot partition basics functions ***********************/
|
|
static uint32_t dev_param_gen_list(dev_param_t *param,
|
|
const char *name, const char *value)
|
|
{
|
|
uint32_t len_name, len_value;
|
|
|
|
len_name = iot_strlen(name);
|
|
len_value = iot_strlen(value);
|
|
if (len_name >= PARAM_NAME_LEN_MAX || len_value > PARAM_VAL_LEN_MAX) {
|
|
return 1;
|
|
}
|
|
|
|
os_mem_cpy(param->name, name, len_name);
|
|
os_mem_cpy(param->value, value, len_value);
|
|
param->equal = PARAM_EQUAL_CHAR;
|
|
param->end = PARAM_END_CHAR;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static uint32_t dev_param_create_value(const char *name, char *value)
|
|
{
|
|
int i = 0;
|
|
int fd = 0;
|
|
uint32_t ret = 1;
|
|
int name_len = 0;
|
|
int pos = 0;
|
|
dev_param_t param = {0};
|
|
|
|
name_len = iot_strlen(name);
|
|
fd = dev_open(PART_NUM_PARAM, 0);
|
|
if (fd < 0) {
|
|
iot_printf("open part %d failed\n", PART_NUM_PARAM);
|
|
goto out;
|
|
}
|
|
|
|
for (i = 0; i < PARAM_MAX_LENGTH; i++) {
|
|
os_mem_set(¶m, 0, sizeof(dev_param_t));
|
|
if (dev_read(fd, ¶m, sizeof(dev_param_t)) < 0) {
|
|
iot_printf("read part parameters failed\n");
|
|
goto out;
|
|
}
|
|
if (param.end == PARAM_END_CHAR) {
|
|
if (os_mem_cmp(name, param.name, name_len) == 0) {
|
|
ret = 0;
|
|
goto out;
|
|
}
|
|
} else {
|
|
os_mem_set(¶m, 0, sizeof(dev_param_t));
|
|
if (dev_param_gen_list(¶m, name, value)) {
|
|
goto out;
|
|
}
|
|
|
|
pos += sizeof(dev_param_t) * i;
|
|
dev_seek(fd, pos, DEV_SEEK_SET);
|
|
if (dev_write(fd, ¶m,sizeof(dev_param_t)) < 0) {
|
|
iot_printf("write param[%s=%s] failed\n", name, value);
|
|
goto out;
|
|
}
|
|
ret = 0;
|
|
goto out;
|
|
}
|
|
}
|
|
out:
|
|
dev_close(fd);
|
|
return ret;
|
|
}
|
|
|
|
uint32_t dev_param_get_value(const char *name, char *value, int *pos)
|
|
{
|
|
int i = 0;
|
|
int fd = 0;
|
|
uint32_t ret = 1;
|
|
int name_len = 0;
|
|
int value_len = 0;
|
|
dev_param_t param = {0};
|
|
|
|
if (name == NULL || pos == NULL) {\
|
|
goto out;
|
|
}
|
|
|
|
name_len = iot_strlen(name);
|
|
fd = dev_open(PART_NUM_PARAM, 0);
|
|
if (fd < 0) {
|
|
iot_printf("open part %d failed\n", PART_NUM_PARAM);\
|
|
goto out;
|
|
}
|
|
|
|
for (i = 0; i < PARAM_MAX_LENGTH; i++) {
|
|
os_mem_set(¶m, 0, sizeof(dev_param_t));
|
|
if (dev_read(fd, ¶m, sizeof(dev_param_t)) < 0) {
|
|
iot_printf("read part parameters failed\n");
|
|
goto out;
|
|
}
|
|
if (param.end == PARAM_END_CHAR) {
|
|
if (os_mem_cmp(name, param.name, name_len) == 0) {
|
|
value_len = iot_strlen(param.value);
|
|
os_mem_cpy(value, param.value, value_len);
|
|
*pos = dev_seek(fd, 0, DEV_SEEK_CUR);
|
|
*pos -= sizeof(dev_param_t);
|
|
ret = 0;
|
|
goto out;
|
|
}
|
|
} else {
|
|
iot_printf("part parameters not found\n");\
|
|
goto out;
|
|
}
|
|
}
|
|
out:
|
|
dev_close(fd);
|
|
return ret;
|
|
}
|
|
|
|
uint32_t dev_param_save_value(const char *name, char *value)
|
|
{
|
|
int fd = 0;
|
|
int pos = 0;
|
|
uint32_t ret = 1;
|
|
dev_param_t param = {0};
|
|
char tmp[PARAM_VAL_LEN_MAX] = {0};
|
|
int name_len = iot_strlen(name);
|
|
|
|
if (name == NULL && value == NULL) {
|
|
goto out;
|
|
}
|
|
|
|
if (dev_param_get_value(name, tmp, &pos)) {
|
|
if ((os_mem_cmp(name, PARAM_STRING_UPGRADE_STS, name_len) == 0)) {
|
|
ret = dev_param_create_value(name, value);
|
|
goto out;
|
|
} else {
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
if ((iot_strlen(value) == iot_strlen(tmp))
|
|
&& (os_mem_cmp(tmp, value, iot_strlen(value)) == 0)) {
|
|
ret = 0;
|
|
goto out;
|
|
}
|
|
|
|
if (dev_param_gen_list(¶m, name, value)) {
|
|
goto out;
|
|
}
|
|
fd = dev_open(PART_NUM_PARAM, 0);
|
|
if (fd < 0) {
|
|
iot_printf("open part %d failed\n", PART_NUM_PARAM);
|
|
dev_close(fd);
|
|
goto out;
|
|
}
|
|
dev_seek(fd, pos, DEV_SEEK_SET);
|
|
|
|
if (dev_write(fd, ¶m,sizeof(dev_param_t)) < 0) {
|
|
iot_printf("write param[%s=%s] failed\n", name, value);
|
|
dev_close(fd);
|
|
IOT_ASSERT(0);
|
|
goto out;
|
|
}
|
|
|
|
dev_close(fd);
|
|
ret = 0;
|
|
|
|
out:
|
|
return ret;
|
|
}
|
|
|
|
/************************* boot parameter functions ***************************/
|
|
uint8_t dev_get_first_boot_val()
|
|
{
|
|
return g_first_boot;
|
|
}
|
|
|
|
uint8_t dev_get_first_run_val()
|
|
{
|
|
return g_first_run;
|
|
}
|
|
|
|
uint8_t dev_get_boot_cnt()
|
|
{
|
|
return g_cnt_flag;
|
|
}
|
|
|
|
bool_t dev_get_upgrade_flag(void)
|
|
{
|
|
return g_upgrade_flag;
|
|
}
|
|
|
|
static uint32_t dev_param_get_flag(const char *name, uint32_t *flag)
|
|
{
|
|
int pos = 0;
|
|
char value[PARAM_VAL_LEN_MAX] = {0};
|
|
|
|
if (dev_param_get_value(name, value, &pos)) {
|
|
iot_printf("get %s flag value error\n", name);
|
|
return 1;
|
|
}
|
|
|
|
// check valid number, ascii range is '0' - '9'
|
|
if ((value[0] < 0x30) || (value[0] > 0x39)) {
|
|
iot_printf("invalid parameter value: %s\n", value);
|
|
return 1;
|
|
}
|
|
|
|
*flag = value[0] - 0x30;
|
|
|
|
return 0;
|
|
}
|
|
|
|
uint32_t dev_param_get_start_flag(uint32_t *flag)
|
|
{
|
|
return dev_param_get_flag(PARAM_STRING_START_PART, flag);
|
|
}
|
|
|
|
uint32_t dev_param_get_uncp_flag(uint32_t *flag)
|
|
{
|
|
return dev_param_get_flag(PARAM_STRING_FW_UNCP, flag);
|
|
}
|
|
|
|
uint32_t dev_param_get_last_flag(uint32_t *flag)
|
|
{
|
|
return dev_param_get_flag(PARAM_STRING_LAST_PART, flag);
|
|
}
|
|
|
|
uint32_t dev_param_get_boot_flag(uint32_t *flag)
|
|
{
|
|
return dev_param_get_flag(PARAM_STRING_BOOT_PART, flag);
|
|
}
|
|
|
|
uint32_t dev_param_get_cnt_flag(uint32_t *flag)
|
|
{
|
|
return dev_param_get_flag(PARAM_STRING_BOOT_CNT, flag);
|
|
}
|
|
|
|
uint32_t dev_param_get_boot_after_burn(uint32_t *p_flag)
|
|
{
|
|
if (dev_param_get_flag(PARAM_STRING_FIRST_RUN, p_flag)) {
|
|
iot_printf("get first run flag value error\n");
|
|
return ERR_FAIL;
|
|
}
|
|
/* If the startup is the first after burning, save the flag.
|
|
* do not use the p_flag, because it will be clean up later.
|
|
*/
|
|
if (*p_flag) {
|
|
g_first_run = 1;
|
|
}
|
|
|
|
return ERR_OK;
|
|
}
|
|
|
|
uint32_t dev_param_clear_boot_after_burn(void)
|
|
{
|
|
uint32_t flag = ERR_OK;
|
|
/* when FW starts, the "first_run" field is cleared */
|
|
if (dev_param_get_boot_after_burn(&flag) != ERR_OK) {
|
|
return ERR_OK;
|
|
}
|
|
if (dev_param_save_value(PARAM_STRING_FIRST_RUN, "0") != ERR_OK) {
|
|
return ERR_FAIL;
|
|
}
|
|
return ERR_OK;
|
|
}
|
|
|
|
void dev_switch_part_flag(uint8_t cause)
|
|
{
|
|
char switch_info;
|
|
|
|
if (g_last_flag == 0) {
|
|
dev_param_save_value(PARAM_STRING_START_PART, "1");
|
|
} else if (g_last_flag == 1) {
|
|
dev_param_save_value(PARAM_STRING_START_PART, "0");
|
|
}
|
|
/* valid param check */
|
|
dev_param_save_value(PARAM_STRING_BOOT_PART, "1");
|
|
|
|
if (cause != DEV_SWITCH_PART_CAUSE_CRASH) {
|
|
switch_info = '0' + (cause * 2 + g_last_flag);
|
|
dev_param_save_value(PARAM_STRING_SWITCH_INFO, &switch_info);
|
|
}
|
|
|
|
if (cause == DEV_SWITCH_PART_CAUSE_UPGRADE) {
|
|
iot_printf("upgrade is complete, current part:%d\n", g_last_flag);
|
|
}
|
|
}
|
|
|
|
void dev_switch_part()
|
|
{
|
|
if (g_cnt_flag == 0) {
|
|
// if cnt is not cleared, don't run switch part
|
|
flash_set_os_dis();
|
|
dev_switch_part_flag(DEV_SWITCH_PART_CAUSE_CRASH);
|
|
flash_set_os_ena();
|
|
}
|
|
}
|
|
|
|
void dev_get_switch_part_info(uint8_t *cause, uint8_t *upgrade_flag)
|
|
{
|
|
uint32_t switch_info = 0;
|
|
uint8_t last_pass_part = 0, switch_cause = 0;
|
|
|
|
/* default value */
|
|
*cause = DEV_SWITCH_PART_CAUSE_UPGRADE;
|
|
*upgrade_flag = 1;
|
|
|
|
if (dev_param_get_flag(PARAM_STRING_SWITCH_INFO, &switch_info)) {
|
|
/* the parameter does not exist(old version) */
|
|
return;
|
|
}
|
|
|
|
switch_cause = switch_info / 2;
|
|
last_pass_part = switch_info % 2;
|
|
|
|
if (switch_cause >= DEV_SWITCH_PART_CAUSE_MAX) {
|
|
/* invalid value */
|
|
return;
|
|
}
|
|
*cause = switch_cause;
|
|
|
|
if (g_start_flag == last_pass_part) {
|
|
*upgrade_flag = 0;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
uint32_t dev_startup_param_value_check(bool_t sync)
|
|
{
|
|
uint32_t boot = 0;
|
|
uint32_t start = 0;
|
|
uint32_t last = 0;
|
|
uint32_t cnt = 0;
|
|
uint32_t ret = HAL_ERROR;
|
|
uint32_t failed_pos = 0;
|
|
|
|
if (dev_param_get_start_flag(&start)) {
|
|
failed_pos = 1;
|
|
goto err_exit;
|
|
}
|
|
if (dev_param_get_last_flag(&last)) {
|
|
failed_pos = 2;
|
|
goto err_exit;
|
|
}
|
|
if (dev_param_get_boot_flag(&boot)) {
|
|
failed_pos = 3;
|
|
goto err_exit;
|
|
}
|
|
if (dev_param_get_cnt_flag(&cnt)) {
|
|
// boot_cnt not found, set cnt as default
|
|
cnt = 0;
|
|
}
|
|
g_start_flag = start;
|
|
g_last_flag = last;
|
|
g_cnt_flag = cnt;
|
|
iot_printf("boot: %d, start: %d, last: %d\n", boot, start, last);
|
|
iot_printf("boot cnt: %d\n", cnt);
|
|
|
|
if (last != start) {
|
|
g_upgrade_flag = true;
|
|
if (0 == last) {
|
|
if (sync) {
|
|
iot_printf("start=1, then set start=0\n");
|
|
dev_param_save_value(PARAM_STRING_START_PART, "0");
|
|
g_start_flag = 0;
|
|
}
|
|
ret = HAL_OK;
|
|
} else if (1 == last) {
|
|
if (sync) {
|
|
iot_printf("start=0, then set start=1\n");
|
|
dev_param_save_value(PARAM_STRING_START_PART, "1");
|
|
g_start_flag = 1;
|
|
}
|
|
ret = HAL_OK;
|
|
} else {
|
|
failed_pos = 4;
|
|
goto err_exit;
|
|
}
|
|
}
|
|
|
|
if (cnt && sync) {
|
|
iot_printf("boot cnt=%d, then set cnt=0\n", cnt);
|
|
dev_param_save_value(PARAM_STRING_BOOT_CNT, "0");
|
|
g_cnt_flag = 0;
|
|
}
|
|
|
|
if (boot && sync) {
|
|
if (g_first_boot == 0) {
|
|
g_first_boot = 1;
|
|
}
|
|
iot_printf("boot=1, then set boot=0\n");
|
|
dev_param_save_value(PARAM_STRING_BOOT_PART, "0");
|
|
}
|
|
|
|
err_exit:
|
|
iot_printf("startup param value check, failed_pos %d, ret %d \n",
|
|
failed_pos, ret);
|
|
return ret;
|
|
}
|
|
|
|
/**************************** firmware functions ******************************/
|
|
/**
|
|
* @brief mtd_get_fw_decompressed_crc(): get crc of decompressed firmware.
|
|
* @param part: fw1 or fw2 partition.
|
|
* @return 0: failed; other: decompressed firmware crc.
|
|
*/
|
|
static uint32_t mtd_get_fw_decompressed_crc(uint8_t part)
|
|
{
|
|
imgHdr hdr = {0};
|
|
|
|
if (mtd_get_hdr(part, &hdr) != ERR_OK) {
|
|
return 0;
|
|
}
|
|
|
|
if (hdrVer_10 == iot_imghdr_get_hdrVer(&hdr)) {
|
|
/* [TODO]: get header info form psram chip */
|
|
if (mtd_get_hdr(PART_NUM_RUN, &hdr) != ERR_OK) {
|
|
return 0;
|
|
}
|
|
return iot_imghdr_get_imgCRC(&hdr);
|
|
} else {
|
|
return iot_imghdr_get_fwCRC(&hdr);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief mtd_get_fw_decompressed_size(): get size of decompressed firmware.
|
|
* @param part: fw1 or fw2 partition.
|
|
* @return 0: failed; other: decompressed firmware size.
|
|
*/
|
|
static uint32_t mtd_get_fw_decompressed_size(uint8_t part)
|
|
{
|
|
imgHdr hdr = {0};
|
|
|
|
if (mtd_get_hdr(part, &hdr) != ERR_OK) {
|
|
return 0;
|
|
}
|
|
|
|
if (hdrVer_10 == iot_imghdr_get_hdrVer(&hdr)) {
|
|
/* [TODO]: get header info form psram chip */
|
|
if (mtd_get_hdr(PART_NUM_RUN, &hdr) != ERR_OK) {
|
|
return 0;
|
|
}
|
|
return iot_imghdr_get_imgSize(&hdr);
|
|
} else {
|
|
return iot_imghdr_get_fwSize(&hdr);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief mtd_calc_part_crc_internal(): calculate firmware crc for specified part.
|
|
* @param part: the specified partition.
|
|
* @return 0: failed; other: firmware crc.
|
|
*/
|
|
static uint32_t mtd_calc_part_crc_internal(uint8_t part_num)
|
|
{
|
|
#define READ_BUFF_SIZE (0x100)
|
|
iot_pkt_t *pkt = NULL;
|
|
uint32_t size_crc = 0, crc_cal = 0xffffffff;
|
|
uint32_t calc_pos = 0, calc_size, end_pos = 0;
|
|
uint8_t pib_upgrade_part = 0;
|
|
uint8_t *block = NULL;
|
|
imgHdr hdr = {0};
|
|
int fd;
|
|
|
|
if (dev_get_upgrade_pib_part_num(&pib_upgrade_part)) {
|
|
iot_printf("get pib upgrade part number failed\n");
|
|
return 0;
|
|
}
|
|
|
|
pkt = iot_pkt_alloc(READ_BUFF_SIZE, IOT_DRIVER_MID);
|
|
if (pkt == NULL) {
|
|
iot_printf("memory malloc failed.\n");
|
|
return 0;
|
|
}
|
|
block = iot_pkt_data(pkt);
|
|
|
|
if (part_num == PART_NUM_RUN) {
|
|
/* kl1 kl2 run partition not has header information, but kl3 has it */
|
|
if (g_start_flag) {
|
|
size_crc = mtd_get_fw_decompressed_size(g_part_num_fw2);
|
|
mtd_get_hdr(g_part_num_fw2, &hdr);
|
|
} else {
|
|
size_crc = mtd_get_fw_decompressed_size(g_part_num_fw1);
|
|
mtd_get_hdr(g_part_num_fw1, &hdr);
|
|
}
|
|
|
|
/* kl3 need IMAGE_LEN_FOR_CRC */
|
|
if (hdrVer_10 == iot_imghdr_get_hdrVer(&hdr)) {
|
|
size_crc = IMAGE_LEN_FOR_CRC(size_crc);
|
|
}
|
|
} else {
|
|
size_crc = mtd_get_hdr_img_size(part_num);
|
|
size_crc = IMAGE_LEN_FOR_CRC(size_crc);
|
|
}
|
|
|
|
fd = dev_open(part_num, 0);
|
|
if (fd < 0) {
|
|
iot_pkt_free(pkt);
|
|
return 0;
|
|
}
|
|
|
|
/* skip header area */
|
|
calc_pos = sizeof(imgHdr);
|
|
dev_seek(fd, calc_pos, DEV_SEEK_SET);
|
|
end_pos = size_crc + calc_pos;
|
|
|
|
if (part_num == pib_upgrade_part) {
|
|
/* PIB firmware only needs to verify ro data (first 4KB) */
|
|
while (calc_pos < IOT_PIB_W_SECTION_START_ADDR) {
|
|
calc_size = min(READ_BUFF_SIZE, IOT_PIB_W_SECTION_START_ADDR -
|
|
calc_pos);
|
|
dev_read(fd, block, calc_size);
|
|
crc_cal = iot_getcrc32_update(crc_cal, block, calc_size);
|
|
calc_pos += calc_size;
|
|
}
|
|
os_mem_set(block, 0, READ_BUFF_SIZE);
|
|
while (calc_pos < end_pos) {
|
|
calc_size = min(READ_BUFF_SIZE, end_pos - calc_pos);
|
|
crc_cal = iot_getcrc32_update(crc_cal, block, calc_size);
|
|
calc_pos += calc_size;
|
|
}
|
|
} else {
|
|
while (calc_pos < end_pos) {
|
|
calc_size = min(READ_BUFF_SIZE, end_pos - calc_pos);
|
|
dev_read(fd, block, calc_size);
|
|
crc_cal = iot_getcrc32_update(crc_cal, block, calc_size);
|
|
calc_pos += calc_size;
|
|
}
|
|
}
|
|
|
|
dev_close(fd);
|
|
iot_pkt_free(pkt);
|
|
|
|
return (crc_cal ^ 0xffffffff);
|
|
}
|
|
|
|
uint32_t mtd_calc_decompressed_fw_crc_mp(uint8_t part)
|
|
{
|
|
uint8_t *src, *buf, *p;
|
|
uint32_t size_crc, crc_cal = 0xffffffff;
|
|
uint32_t left = 0, len = 0;
|
|
uint8_t first = 1;
|
|
imgHdr hdr = {0};
|
|
|
|
#define BLOCK_SIZE 0x4000
|
|
|
|
src = (uint8_t *)(g_part_info[PART_NUM_RUN].offset + flash_get_dev_base());
|
|
buf = os_mem_malloc(IOT_DRIVER_MID, BLOCK_SIZE);
|
|
if(buf == NULL) {
|
|
iot_printf("memory malloc failed.\n");
|
|
return 0;
|
|
}
|
|
size_crc = mtd_get_fw_decompressed_size(part);
|
|
|
|
left = size_crc;
|
|
p = src + sizeof(imgHdr);
|
|
|
|
if (ERR_OK != mtd_get_hdr(part, &hdr)) {
|
|
iot_printf("get fw hdr failed\n");
|
|
os_mem_free(buf);
|
|
return 0;
|
|
}
|
|
|
|
/* kl3 need IMAGE_LEN_FOR_CRC */
|
|
if (hdrVer_10 == iot_imghdr_get_hdrVer(&hdr)) {
|
|
left = IMAGE_LEN_FOR_CRC(size_crc);
|
|
}
|
|
|
|
os_disable_irq();
|
|
|
|
while (left > 0) {
|
|
// read data by block
|
|
if(first){
|
|
len = 13;
|
|
first = 0;
|
|
} else {
|
|
len = BLOCK_SIZE;
|
|
}
|
|
len = (len > left) ? left : len;
|
|
|
|
// copy to data buffer;
|
|
os_mem_cpy(buf, p, len);
|
|
|
|
crc_cal = iot_getcrc32_update(crc_cal, buf, len);
|
|
|
|
left = left - len;
|
|
p = p + len;
|
|
}
|
|
|
|
os_enable_irq();
|
|
|
|
os_mem_free(buf);
|
|
|
|
crc_cal ^= 0xffffffff;
|
|
|
|
return crc_cal;
|
|
}
|
|
|
|
uint32_t mtd_calc_hdr_img_part_crc(uint8_t part)
|
|
{
|
|
return mtd_calc_part_crc_internal(part);
|
|
}
|
|
|
|
uint8_t mtd_fw_hdr_img_crc_compare()
|
|
{
|
|
uint8_t ret = 0;
|
|
uint32_t ori_hdr_crc = 0;
|
|
uint32_t calc_hdr_crc = 0;
|
|
uint32_t ori_fw_crc = 0;
|
|
uint32_t calc_fw_crc = 0;
|
|
uint8_t fw_part = 0;
|
|
|
|
dev_get_boot_fw_part_num(&fw_part);
|
|
|
|
ori_hdr_crc = mtd_get_hdr_img_crc(fw_part);
|
|
calc_hdr_crc = mtd_calc_hdr_img_part_crc(fw_part);
|
|
|
|
if (!g_run_in_psram) {
|
|
if (fw_part == PART_NUM_FW1 || fw_part == PART_NUM_FW2) {
|
|
ori_fw_crc = mtd_get_fw_decompressed_crc(fw_part);
|
|
if(g_fw_mode == FTM_MODE){
|
|
calc_fw_crc = mtd_calc_decompressed_fw_crc_mp(fw_part);
|
|
} else {
|
|
calc_fw_crc = mtd_calc_part_crc_internal(PART_NUM_RUN);
|
|
}
|
|
}
|
|
}
|
|
if ((ori_hdr_crc == calc_hdr_crc) && (ori_fw_crc == calc_fw_crc)) {
|
|
iot_printf("Matched: fw_hdr_crc=%x; fw_crc=%x.\n", \
|
|
calc_hdr_crc, calc_fw_crc);
|
|
} else {
|
|
ret = 1;
|
|
iot_printf("Mismatched: fw_hdr_crc ori=%x, calc=%x; fw_crc ori=%x, "
|
|
"calc=%x.\n", ori_hdr_crc, calc_hdr_crc, ori_fw_crc, calc_fw_crc);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
uint32_t mtd_copy_part(uint8_t src_part, uint8_t dest_part)
|
|
{
|
|
int fd_s = -1, fd_d = -1;
|
|
int status = 0;
|
|
uint8_t is_erase = 0, is_exist_cus = 0;
|
|
uint8_t boot_fw_part, boot_pib_part, boot_cus_part;
|
|
uint32_t reason = ERR_OK;
|
|
uint32_t offset = 0, write_len = 0;
|
|
uint32_t size_img = 0;
|
|
uint8_t pib_type = 0;
|
|
iot_pkt_t *cache_pkt;
|
|
|
|
cache_pkt = (iot_pkt_t*)iot_pkt_alloc(MTD_COPY_FLASH_SIZE_ONCE,
|
|
IOT_DRIVER_MID);
|
|
if (cache_pkt == NULL) {
|
|
return ERR_NOMEM;
|
|
}
|
|
|
|
if (g_part_info[PART_NUM_CUS_FW1].size &&
|
|
g_part_info[PART_NUM_CUS_FW2].size) {
|
|
is_exist_cus = 1;
|
|
}
|
|
|
|
if (dev_get_boot_fw_part_num(&boot_fw_part)) {
|
|
iot_printf("%s firmware boot part open failed\n", __FUNCTION__);
|
|
} else {
|
|
if (boot_fw_part == dest_part) {
|
|
reason = 1;
|
|
goto err_exit;
|
|
}
|
|
}
|
|
|
|
if (dev_get_boot_pib_part_num(&boot_pib_part)) {
|
|
iot_printf("%s pib boot part open failed\n", __FUNCTION__);
|
|
} else {
|
|
if (boot_pib_part == dest_part) {
|
|
reason = 2;
|
|
goto err_exit;
|
|
}
|
|
}
|
|
|
|
if (is_exist_cus) {
|
|
if (dev_get_boot_cus_part_num(&boot_cus_part)) {
|
|
iot_printf("%s cus boot part open failed\n", __FUNCTION__);
|
|
} else {
|
|
if (boot_cus_part == dest_part) {
|
|
reason = 3;
|
|
goto err_exit;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* kl1, kl2 and kl3 are same; 1m, 2m and 4m are same */
|
|
if (src_part == PART_NUM_PIB1) {
|
|
pib_type = 1;
|
|
if (dest_part != PART_NUM_PIB2) {
|
|
reason = 4;
|
|
}
|
|
} else if (src_part == PART_NUM_PIB2) {
|
|
pib_type = 1;
|
|
if (dest_part != PART_NUM_PIB1) {
|
|
reason = 5;
|
|
}
|
|
} else if (src_part == g_part_num_fw1) {
|
|
if (dest_part != g_part_num_fw2) {
|
|
reason = 6;
|
|
}
|
|
} else if (src_part == g_part_num_fw2) {
|
|
if (dest_part != g_part_num_fw1) {
|
|
reason = 7;
|
|
}
|
|
} else if (src_part == PART_NUM_CUS_FW1) {
|
|
if (dest_part != PART_NUM_CUS_FW2 || !is_exist_cus) {
|
|
reason = 8;
|
|
}
|
|
} else if (src_part == PART_NUM_CUS_FW2) {
|
|
if (dest_part != PART_NUM_CUS_FW1 || !is_exist_cus) {
|
|
reason = 9;
|
|
}
|
|
} else {
|
|
reason = 10;
|
|
}
|
|
|
|
if (reason) {
|
|
goto err_exit;
|
|
}
|
|
|
|
size_img = mtd_get_hdr_img_size(src_part);
|
|
size_img = IMAGE_LEN_FOR_CRC(size_img);
|
|
if (size_img > 0) {
|
|
fd_s = dev_open(src_part, 0);
|
|
if (fd_s < 0) {
|
|
reason = 12;
|
|
goto err_exit;
|
|
}
|
|
fd_d = dev_open(dest_part, 0);
|
|
if (fd_d < 0) {
|
|
reason = 13;
|
|
goto err_exit;
|
|
}
|
|
if (pib_type) {
|
|
size_img = IOT_PIB_W_SECTION_START_ADDR;
|
|
is_erase = 1;
|
|
} else {
|
|
size_img += sizeof(imgHdr);
|
|
status = dev_erase(fd_d, 0, DEV_ERASE_TYPE_FULL_PART);
|
|
}
|
|
if (status < 0) {
|
|
reason = 14;
|
|
goto err_exit;
|
|
}
|
|
while (offset < size_img) {
|
|
iot_wdg_feed_dog();
|
|
write_len = min(MTD_COPY_FLASH_SIZE_ONCE, size_img - offset);
|
|
status = dev_read(fd_s, iot_pkt_data(cache_pkt), write_len);
|
|
if (status < 0) {
|
|
reason = 15;
|
|
goto err_exit;
|
|
}
|
|
status = dev_write_ext(fd_d, iot_pkt_data(cache_pkt), write_len,
|
|
is_erase);
|
|
if (status < 0) {
|
|
reason = 16;
|
|
goto err_exit;
|
|
}
|
|
offset += write_len;
|
|
}
|
|
}
|
|
err_exit:
|
|
if (fd_s >= 0) {
|
|
dev_close(fd_s);
|
|
}
|
|
if (fd_d >= 0) {
|
|
dev_close(fd_d);
|
|
}
|
|
if (cache_pkt != NULL) {
|
|
iot_pkt_free(cache_pkt);
|
|
}
|
|
iot_printf("%s copy part result:%d\n", __FUNCTION__, reason);
|
|
if (reason) {
|
|
return ERR_FAIL;
|
|
}
|
|
return ERR_OK;
|
|
}
|
|
|
|
uint32_t mtd_running_fw_get_size(void)
|
|
{
|
|
uint32_t curr_run_part = 0;
|
|
uint32_t size = 0;
|
|
|
|
if (g_last_flag == 0) {
|
|
curr_run_part = g_part_num_fw1;
|
|
} else if (g_last_flag == 1) {
|
|
curr_run_part = g_part_num_fw2;
|
|
} else {
|
|
return 0;
|
|
}
|
|
|
|
size = mtd_get_hdr_img_size(curr_run_part);
|
|
if (size == 0) {
|
|
return 0;
|
|
}
|
|
size += HEADER_TOLTAL_SIZE;
|
|
|
|
if (size > g_part_info[curr_run_part].size) {
|
|
size = g_part_info[curr_run_part].size;
|
|
}
|
|
|
|
return size;
|
|
}
|
|
|
|
uint32_t mtd_running_fw_read(uint32_t offset, uint8_t *buffer,
|
|
uint32_t length)
|
|
{
|
|
uint8_t ret = ERR_FAIL;
|
|
static uint32_t image_size = 0;
|
|
uint32_t read_len = 0;
|
|
uint32_t curr_run_part = 0;
|
|
|
|
if (buffer == NULL || length == 0) {
|
|
goto out;
|
|
}
|
|
|
|
if (image_size == 0) {
|
|
image_size = mtd_running_fw_get_size();
|
|
if (image_size == 0) {
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
if (offset > image_size) {
|
|
goto out;
|
|
}
|
|
if (offset + length > image_size) {
|
|
length = image_size - offset;
|
|
}
|
|
|
|
if (g_last_flag == 0) {
|
|
curr_run_part = g_part_num_fw1;
|
|
} else if (g_last_flag == 1) {
|
|
curr_run_part = g_part_num_fw2;
|
|
} else {
|
|
goto out;
|
|
}
|
|
|
|
offset += g_part_info[curr_run_part].offset;
|
|
|
|
if (FLASH_OS_ENABLE == flash_os_is_enable()) {
|
|
os_acquire_mutex(mtd_op_mutex);
|
|
}
|
|
ret = flash_read(buffer, offset, length, MOD_SFC_READ_QUAD_FAST);
|
|
if (FLASH_OS_ENABLE == flash_os_is_enable()) {
|
|
os_release_mutex(mtd_op_mutex);
|
|
}
|
|
if (ret != HAL_OK) {
|
|
goto out;
|
|
}
|
|
read_len = length;
|
|
out:
|
|
return read_len;
|
|
}
|
|
|
|
/************************* custom partition functions *************************/
|
|
uint32_t custom_dev_resize(uint32_t offset, uint32_t size)
|
|
{
|
|
if (offset < 0x200000) {
|
|
return HAL_ERROR;
|
|
}
|
|
if (size > 0x5e0000) {
|
|
return HAL_ERROR;
|
|
}
|
|
g_part_info[PART_NUM_CUS_DATA].offset = offset;
|
|
g_part_info[PART_NUM_CUS_DATA].size = size;
|
|
|
|
return HAL_OK;
|
|
}
|
|
|
|
uint32_t custom_dev_query_offset()
|
|
{
|
|
return g_part_info[PART_NUM_CUS_DATA].offset;
|
|
}
|
|
|
|
int32_t custom_dev_query_rw_size()
|
|
{
|
|
return g_part_info[PART_NUM_CUS_DATA].size;
|
|
}
|
|
|
|
int32_t custom_dev_open()
|
|
{
|
|
int fd = 0;
|
|
|
|
fd = dev_open(PART_NUM_CUS_DATA, 0);
|
|
if (fd < 0) {
|
|
iot_printf("open custom part failed\n");
|
|
return -1;
|
|
}
|
|
|
|
return fd;
|
|
}
|
|
|
|
int32_t custom_dev_close(int32_t fd)
|
|
{
|
|
if (fd != PART_NUM_CUS_DATA) {
|
|
return -1;
|
|
}
|
|
|
|
return dev_close(fd);
|
|
}
|
|
|
|
int32_t custom_dev_seek(int32_t fd, uint32_t offset, uint8_t fromwhere)
|
|
{
|
|
if (fd != PART_NUM_CUS_DATA) {
|
|
return -1;
|
|
}
|
|
|
|
return dev_seek(fd, offset, fromwhere);
|
|
}
|
|
|
|
int32_t custom_dev_read(int32_t fd, void* buf, size_t count)
|
|
{
|
|
if (fd != PART_NUM_CUS_DATA) {
|
|
return -1;
|
|
}
|
|
|
|
return dev_read(fd, buf, count);
|
|
}
|
|
|
|
int32_t custom_dev_write(int32_t fd, void*buf, size_t count)
|
|
{
|
|
if (fd != PART_NUM_CUS_DATA) {
|
|
return -1;
|
|
}
|
|
|
|
return dev_write(fd, buf, count);
|
|
}
|
|
|
|
int32_t custom_dev_write_without_erase(int32_t fd, void*buf,
|
|
size_t count)
|
|
{
|
|
if (fd != PART_NUM_CUS_DATA) {
|
|
return -1;
|
|
}
|
|
|
|
return dev_write_ext(fd, buf, count, 0);
|
|
}
|
|
|
|
int32_t custom_dev_erase(int32_t fd, uint32_t offset, size_t count)
|
|
{
|
|
uint8_t mode;
|
|
uint32_t erase_len;
|
|
|
|
if (fd != PART_NUM_CUS_DATA) {
|
|
return -1;
|
|
}
|
|
|
|
if ((mtd_get_size_of_erase_once(fd) == PAGE_PROGRAM_SIZE)
|
|
&& ((count & (PAGE_ERASE_SIZE - 1)) == 0)) {
|
|
mode = MODE_ERASE_PAGE;
|
|
erase_len = PAGE_ERASE_SIZE;
|
|
} else {
|
|
mode = MODE_ERASE_SECTOR;
|
|
erase_len = SECTOR_ERASE_SIZE;
|
|
}
|
|
if (offset & (erase_len - 1) ){
|
|
return -1;
|
|
}
|
|
|
|
if (count & (erase_len - 1) ){
|
|
return -1;
|
|
}
|
|
while(count > 0){
|
|
if (dev_erase(fd, offset, mode) < 0){
|
|
return -1;
|
|
}
|
|
offset += erase_len;
|
|
count -= erase_len;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int32_t custom_dev_get_size_of_erase_once(int32_t fd)
|
|
{
|
|
if (fd != PART_NUM_CUS_DATA) {
|
|
return -1;
|
|
}
|
|
|
|
return mtd_get_size_of_erase_once(fd);
|
|
}
|
|
|
|
/***************************** special functions ******************************/
|
|
static uint32_t mtd_part_reinforce(uint32_t offset, uint32_t len)
|
|
{
|
|
uint32_t ret = 0;
|
|
|
|
/* feed watchdog */
|
|
iot_wdg_feed_dog();
|
|
ret = flash_data_reinforce(offset, len);
|
|
|
|
return (ret ? ERR_FAIL : ERR_OK);
|
|
}
|
|
|
|
/**
|
|
* @brief mtd_patch_for_puya() - data reinforce for some flash chips of Puya.
|
|
when we run flash reinforce logic for the first time, we will reinforce
|
|
all partitions except LOG1\LOG2, PIB1\PIB2(backup each other),
|
|
PARAM2(not used), SP_FW1\SP_FW2(not used).
|
|
reinforce the param partition after each restart,
|
|
and reinforce the run partition after each switch boot area (flash module).
|
|
* @return ERR_OK - operation successful, ERR_FAIL - operation failed.
|
|
*/
|
|
int32_t mtd_patch_for_puya(void)
|
|
{
|
|
uint32_t flag_reinforced = 0xff;
|
|
uint32_t ret = 0;
|
|
uint32_t offset = 0, size = 0;
|
|
uint8_t part_num = 0;
|
|
uint32_t boot = 0, start = 0;
|
|
int32_t result = ERR_FAIL;
|
|
uint8_t os_disable = 0;
|
|
|
|
if (patch_puya_twicewrite_flag_check() == 0) {
|
|
result = ERR_OK;
|
|
goto out;
|
|
}
|
|
|
|
ret = dev_param_get_flag(PARAM_STRING_REINFORCE, &flag_reinforced);
|
|
if (ret == 0 && flag_reinforced == 0) {
|
|
//reinforced, do nothing
|
|
} else if (ret == 0 && flag_reinforced == 1) {
|
|
/* always reinforce param partition after restart */
|
|
offset = g_part_info[PART_NUM_PARAM].offset;
|
|
size = g_part_info[PART_NUM_PARAM].size;
|
|
if (mtd_part_reinforce(offset, size)) {
|
|
goto out;
|
|
}
|
|
|
|
if (dev_param_get_boot_flag(&boot)) {
|
|
goto out;
|
|
}
|
|
if (dev_param_get_start_flag(&start)) {
|
|
goto out;
|
|
}
|
|
/* reinforce the run partition if the startup area is switched */
|
|
if (!g_run_in_psram && boot == 1) {
|
|
offset = g_part_info[PART_NUM_RUN].offset;
|
|
if (start) {
|
|
size = mtd_get_fw_decompressed_size(g_part_num_fw2);
|
|
} else {
|
|
size = mtd_get_fw_decompressed_size(g_part_num_fw1);
|
|
}
|
|
if (mtd_part_reinforce(offset, size)) {
|
|
goto out;
|
|
}
|
|
}
|
|
} else {
|
|
/* in 1m, 2m and 4m layout,
|
|
* SP, SBL, PARAM, PIB and OEM partition information are the same.
|
|
*/
|
|
for (part_num = PART_NUM_MIN; part_num < PART_NUM_MAX; part_num++) {
|
|
/* do not reinforce log and pib partition */
|
|
if (part_num == PART_NUM_LOG1 || part_num == PART_NUM_LOG2
|
|
|| part_num == PART_NUM_PIB1 || part_num == PART_NUM_PIB2) {
|
|
continue;
|
|
}
|
|
offset = g_part_info[part_num].offset;
|
|
size = g_part_info[part_num].size;
|
|
/* partition for storing firmware only needs to be reinforced
|
|
* according to the size of firmware.
|
|
*/
|
|
if (part_num == PART_NUM_SP || part_num == PART_NUM_SBL ||
|
|
part_num == PART_NUM_FW1 || part_num == PART_NUM_FW2 ||
|
|
part_num == PART_NUM_CUS_FW1 || part_num == PART_NUM_CUS_FW2 ||
|
|
part_num == PART_NUM_RUN || part_num == PART_NUM_SBL2) {
|
|
if (part_num == PART_NUM_RUN) {
|
|
if (start) {
|
|
size = mtd_get_fw_decompressed_size(g_part_num_fw2);
|
|
} else {
|
|
size = mtd_get_fw_decompressed_size(g_part_num_fw1);
|
|
}
|
|
} else {
|
|
size = mtd_get_hdr_img_size(part_num);
|
|
}
|
|
}
|
|
if (mtd_part_reinforce(offset, size)) {
|
|
goto out;
|
|
}
|
|
}
|
|
/* when running here, the OS has not been started */
|
|
if (FLASH_OS_ENABLE == flash_os_is_enable()) {
|
|
flash_set_os_dis();
|
|
os_disable = 1;
|
|
}
|
|
ret = dev_param_create_value(PARAM_STRING_REINFORCE, "1");
|
|
if (os_disable) {
|
|
flash_set_os_ena();
|
|
}
|
|
if (ret) {
|
|
goto out;
|
|
}
|
|
}
|
|
result = ERR_OK;
|
|
|
|
out:
|
|
return result;
|
|
}
|
|
|