X-Git-Url: https://gerrit.automotivelinux.org/gerrit/gitweb?a=blobdiff_plain;ds=sidebyside;f=service%2Fsystem%2From_access_library%2Flibrary%2Fnor%2Fsrc%2Fnor_backup.c;fp=service%2Fsystem%2From_access_library%2Flibrary%2Fnor%2Fsrc%2Fnor_backup.c;h=8a133b02243c797ab190eafd3b38b4452b1dbd5c;hb=17cf21bcf8a2e29d2cbcf0a313474d2a4ee44f5d;hp=0000000000000000000000000000000000000000;hpb=9e86046cdb356913ae026f616e5bf17f6f238aa5;p=staging%2Fbasesystem.git diff --git a/service/system/rom_access_library/library/nor/src/nor_backup.c b/service/system/rom_access_library/library/nor/src/nor_backup.c new file mode 100755 index 0000000..8a133b0 --- /dev/null +++ b/service/system/rom_access_library/library/nor/src/nor_backup.c @@ -0,0 +1,807 @@ +/* + * @copyright Copyright (c) 2016-2020 TOYOTA MOTOR CORPORATION. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/******************************************************************************* +* $Header:: $ +* $Revision:: $ +*******************************************************************************/ + +/******************************************************************************* +@file mtd_backup.c +@system +@process +@detail + ******************************************************************************/ +#include "system_service/nor_backup.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BACKUP_RETRY_CNT 3 + +/* Invalid Value */ +#define FLSBACKUP_SEMAPHORE_INVALID (0) + + +#define BACKUP_SECTOR_SIZ 1024 // Secter Size + +#define BACKUP_CHECK_OFFSET 16 +#define BACKUP_CHECK_SIZE 12 +#define BACKUP_CHECK_TEXT "MTD_BACKUPDT" +#define BACKUP_CHECK_DAT1 1 // Lower 8bit +#define BACKUP_CHECK_DAT2 2 // Upper 8bit + +#define NOR_ERRLOG(fmt, args...) \ + fprintf(stderr, "[ERR]%ld/%s/%d/= "fmt"\n", syscall(__NR_gettid), __func__, __LINE__, ##args) + +static pthread_mutex_t g_semid_flash = PTHREAD_MUTEX_INITIALIZER; /* Semaphore ID of dram area access */ +static int g_backup_init = FLSBACKUP_SEMAPHORE_INVALID; + +typedef enum { + RET_WT_CHK_OK = 0, + RET_WT_ERR_OTHER, + RET_WT_DEV_ERR, +} NOR_WRITE_BLK_CHK; + +typedef enum { + RET_RD_CHK_OK = 0, + RET_RD_ERR_OTHER, + RET_RD_DEV_ERR, + RET_RD_ERR_1 = -1, + RET_RD_ERR_2 = -2, + RET_RD_ERR_3 = -3, + RET_RD_ERR_4 = -4, +} NOR_READ_BLK_CHK; + +typedef enum { + RET_CHK_OK = 0, + RET_CHK_TEXT_ERR, + RET_CHK_BCC_ERR, +} NOR_BLK_CHK; + +typedef enum { + NOR_IDLE = 0, // 0:Read-out of block data + NOR_ORG_TEXT, // 1:OrgText Error + NOR_ORG_BCC, // 2:OrgBcc error + NOR_READ_OK, // 3:Normal read-out + NOR_READ_END // 4:end state +} NOR_R_STATE; + +typedef enum { + NOR_IDEL = 0, // 0:IDEL + NOR_READ_ERR, // 1:Read Error + NOR_ORG_READ, // 2:Org Read OK + NOR_BAK_WRT, // 3:Bak Write OK + NOR_BACK_READ, // 4:Bak Read OK + NOR_ORG_WRITE, // 5:Org Write OK + NOR_WRITE_END // 6:end state +} NOR_W_STATE; + +NOR_READ_BLK_CHK MtdnBackupReadSub( + const char * path_name, int i_id, int i_offset, int i_size, + void *p_buff, mtd_info_t * mtd_info, int * get_state); +NOR_WRITE_BLK_CHK MtdnBackupWriteSub( + const char * path_name, int i_id, int i_offset, int i_size, + void *p_buff, mtd_info_t * mtd_info); + +int MtdnBackupWriteBase( + const char * path_name, int i_id, int i_offset, int i_size, + void *p_buff, mtd_info_t * mtd_info); +int MtdnBackupReadBase( + const char * path_name, int i_id, int i_offset, int i_size, + void *p_buff, mtd_info_t * mtd_info); + +int MtdBackupInfo(const char * path_name, mtd_info_t * mtd_info); // INFO Get + +NOR_BLK_CHK MtdBackupCheksumRead(char * p_buff, int erase_size, int * ret_sum); // check SUM +int MtdBackupCheksumWrite(char * p_buff, int erase_size); // check SUM + +/*************************************************************************** +@brief mtdn_backup_Read +@outline Read-out of specified block ID +@type Completion return type +@param[in] const char * path_name : (/dev/mtd Device) +@param[in] int i_id : ID...0~ +@param[in] int i_offset : ( i_offset >= 0) +@param[in] int i_size : ( i_size > 0) +@param[in] void *p_buff : (p_buff != NULL) +@return int +@retval 0 : No error +@retval Except : Error +@usage It is Backup API of data read. +*****************************************************************************/ +int mtdn_backup_Read(const char * path_name, int i_id, int i_offset, int i_size, void *p_buff ) { + int ret_status = RET_DEV_NORMAL; + + if (path_name == NULL) { + NOR_ERRLOG("invalid path:%p", path_name); + return RET_DEV_ERR_PARAM; + } + if (p_buff == NULL) { + NOR_ERRLOG("invalid buf:%p", p_buff); + return RET_DEV_ERR_PARAM; + } + if (i_id < 0) { + NOR_ERRLOG("invalid id:%d", i_id); + return RET_DEV_ERR_PARAM; + } + if ((i_offset < 0) || (i_size <= 0)) { + NOR_ERRLOG("invalid size:%d offset:%d", i_size, i_offset); + return RET_DEV_ERR_PARAM; + } + if (g_backup_init == FLSBACKUP_SEMAPHORE_INVALID) { // LCOV_EXCL_BR_LINE 200: g_backup_init is static variable + pthread_mutex_init(&g_semid_flash, NULL); + g_backup_init = ~FLSBACKUP_SEMAPHORE_INVALID; + } + mtd_info_t mtd_info; + memset(&mtd_info, 0, sizeof(mtd_info_t)); + ret_status = MtdBackupInfo((const char *)path_name, &mtd_info); + if (ret_status == RET_DEV_NORMAL) { + if (mtd_info.type != MTD_NORFLASH) { + NOR_ERRLOG("invalid type:%d", mtd_info.type); + ret_status = RET_DEV_ERR_PARAM; + } else { + if ((i_offset + i_size) > (int)(mtd_info.erasesize - BACKUP_CHECK_OFFSET)) { + NOR_ERRLOG("invalid size:%d offset:%d erasesize:%d", i_size, i_offset, mtd_info.erasesize); + ret_status = RET_DEV_ERR_PARAM; + } + } + if (ret_status == RET_DEV_NORMAL) { + /* Start Semaphore(flash) */ + pthread_mutex_lock(&g_semid_flash); + int get_state; // Read status + ret_status = (int)MtdnBackupReadSub(path_name, i_id, i_offset, i_size, + p_buff, &mtd_info, &get_state); + + /* End Semaphore(flash) */ + pthread_mutex_unlock(&g_semid_flash); + } + } + if (ret_status != RET_DEV_NORMAL) { + NOR_ERRLOG("error return:%d", ret_status); + } + return ret_status; +} + +/*************************************************************************** +@brief mtdn_backup_Write +@outline Writing of specified block ID +@type Completion return type +@param[in] const char * path_name : (/dev/mtd Device) +@param[in] int i_id : ID...0~ +@param[in] int i_offset : ( i_offset >= 0) +@param[in] int i_size : ( i_size > 0) +@param[in] void *p_buff : (p_buff != NULL) +@return int +@retval 0 : No error +@retval Except: Error +@usage It is Backup API of data read. +*****************************************************************************/ +int mtdn_backup_Write(const char * path_name, int i_id, int i_offset, int i_size, void *p_buff) { + int ret_status = RET_DEV_NORMAL; + + if (path_name == NULL) { + NOR_ERRLOG("invalid path:%p", path_name); + return RET_DEV_ERR_PARAM; + } + if (p_buff == NULL) { + NOR_ERRLOG("invalid buf:%p", p_buff); + return RET_DEV_ERR_PARAM; + } + if (i_id < 0) { + NOR_ERRLOG("invalid id:%d", i_id); + return RET_DEV_ERR_PARAM; + } + if ((i_offset < 0) || (i_size <= 0)) { + NOR_ERRLOG("invalid size:%d offset:%d", i_size, i_offset); + return RET_DEV_ERR_PARAM; + } + if (g_backup_init == FLSBACKUP_SEMAPHORE_INVALID) { + pthread_mutex_init(&g_semid_flash, NULL); + g_backup_init = ~FLSBACKUP_SEMAPHORE_INVALID; + } + mtd_info_t mtd_info; + memset(&mtd_info, 0, sizeof(mtd_info_t)); + ret_status = MtdBackupInfo((const char *)path_name, &mtd_info); + if (ret_status == RET_DEV_NORMAL) { + if (mtd_info.type != MTD_NORFLASH) { + NOR_ERRLOG("invalid type:%d", mtd_info.type); + ret_status = RET_DEV_ERR_PARAM; + } else if (mtd_info.erasesize == 0) { + NOR_ERRLOG("invalid erasesize:%d", mtd_info.erasesize); + ret_status = RET_DEV_ERR_PARAM; + } else { + if ((i_offset + i_size) > (int)(mtd_info.erasesize - BACKUP_CHECK_OFFSET)) { + NOR_ERRLOG("invalid size:%d offset:%d erasesize:%d", i_size, i_offset, mtd_info.erasesize); + ret_status = RET_DEV_ERR_PARAM; + } + } + if (ret_status == RET_DEV_NORMAL) { + /* Start Semaphore(flash) */ + pthread_mutex_lock(&g_semid_flash); + ret_status = (int)MtdnBackupWriteSub(path_name, i_id, i_offset, i_size, p_buff, &mtd_info); + + /* End Semaphore(flash) */ + pthread_mutex_unlock(&g_semid_flash); + } + } + if (ret_status != RET_DEV_NORMAL) { + NOR_ERRLOG("error return:%d", ret_status); + } + return ret_status; +} + +/*************************************************************************** +@brief MtdnBackupReadSub +@outline Read-out of specified block ID +@type Completion return type +@param[in] const char * path_name : (/dev/mtd Device) +@param[in] int i_id : ID...0~ +@param[in] int i_offset : ( i_offset >= 0) +@param[in] int i_size : ( i_size > 0) +@param[in] void *p_buff : (p_buff != NULL) +@param[in] mtd_info_t * mtd_info : info +@param[in] int * get_state : 0:Rrg Normal 1:Bak Normal +@return NOR_READ_BLK_CHK +@retval RET_RD_CHK_OK : No error +@retval Except : Error +@usage It is Backup API of data read. +*****************************************************************************/ +NOR_READ_BLK_CHK MtdnBackupReadSub(const char * path_name, int i_id, int i_offset, int i_size, + void *p_buff, mtd_info_t * mtd_info, int * get_state) { + NOR_READ_BLK_CHK ret_status = RET_RD_CHK_OK; + char * lp_buffer; + + if (mtd_info->erasesize != 0) { // LCOV_EXCL_BR_LINE 6: double check + lp_buffer = (char *)malloc(mtd_info->erasesize); + if (lp_buffer == NULL) { + NOR_ERRLOG("malloc:%p", lp_buffer); + ret_status = RET_RD_DEV_ERR; // error + } + } else { + // LCOV_EXCL_START 8: dead code + AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert + NOR_ERRLOG("invalid erasesize:%d", mtd_info->erasesize); + ret_status = RET_RD_DEV_ERR; // error + // LCOV_EXCL_STOP + } + if (ret_status == RET_RD_CHK_OK) { + memset(lp_buffer, 0x00, mtd_info->erasesize); + NOR_R_STATE cycle_state = NOR_IDLE; + int block_check_mode = 0; + int ret_sum = 0; + while ((cycle_state < NOR_READ_END) + &&(ret_status == RET_RD_CHK_OK)) { + switch (cycle_state) { + case NOR_IDLE: + // Read-out of block data + if (0 != MtdnBackupReadBase((const char *)path_name, i_id, 0, + (int)mtd_info->erasesize, lp_buffer, mtd_info)) { + ret_status = RET_RD_ERR_OTHER; // Other abnormalities + } else { + NOR_BLK_CHK ret = MtdBackupCheksumRead(lp_buffer, (int)mtd_info->erasesize, (int *)&ret_sum); + if (ret == RET_CHK_TEXT_ERR) { // Text character sequence Abnormalities + cycle_state = NOR_ORG_TEXT; + } else if (ret == RET_CHK_BCC_ERR) { // (BCC)error + cycle_state = NOR_ORG_BCC; + } else { + block_check_mode = 0; // Org Normal + cycle_state = NOR_READ_OK; + } + } + break; + case NOR_ORG_TEXT: // OrgText Error + // Read-out of block data + if (0 != MtdnBackupReadBase((const char *)path_name, (i_id+1), 0, + (int)mtd_info->erasesize, lp_buffer, mtd_info)) { + // other error + AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert + ret_status = RET_RD_ERR_OTHER; // LCOV_EXCL_LINE 5: c API error case. + } else { + NOR_BLK_CHK ret = MtdBackupCheksumRead(lp_buffer, (int)mtd_info->erasesize, + (int *)&ret_sum); // check SUM + if (ret == RET_CHK_TEXT_ERR) { // Text character sequence Abnormalities + ret_status = RET_RD_ERR_1; // Uninitialized. + } else if (ret == RET_CHK_BCC_ERR) { // BCC error + ret_status = RET_RD_ERR_2; // write error + } + block_check_mode = 1; // Bak Normal + cycle_state = NOR_READ_OK; + } + break; + case NOR_ORG_BCC: // OrgBcc error + // Read-out of block data + if (0 != MtdnBackupReadBase((const char *)path_name, (i_id+1), 0, + (int)mtd_info->erasesize, lp_buffer, mtd_info)) { + // other error + AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert + ret_status = RET_RD_ERR_OTHER; // LCOV_EXCL_LINE 5: c API error case. + } else { + NOR_BLK_CHK ret = MtdBackupCheksumRead(lp_buffer, (int)mtd_info->erasesize, + (int *)&ret_sum); // check SUM + if (ret == RET_CHK_TEXT_ERR) { // Text character sequence Abnormalities + ret_status = RET_RD_ERR_3; // write error + } else if (ret == RET_CHK_BCC_ERR) { // BCC error + ret_status = RET_RD_ERR_4; // write error + } + block_check_mode = 1; // Bak Normal + cycle_state = NOR_READ_OK; + } + break; + case NOR_READ_OK: // Normal read-out + // The pickup of the read data + memcpy(p_buff, &lp_buffer[i_offset], (size_t)i_size); + cycle_state = NOR_READ_END; + break; + default: + // LCOV_EXCL_START 8: dead code + AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert + NOR_ERRLOG("invalid state:%d", cycle_state); + // other error + ret_status = RET_RD_ERR_OTHER; + break; + // LCOV_EXCL_STOP + } + } + *get_state = block_check_mode; // 0:OrgNormal 1:BakNormal + free(lp_buffer); + } + return ret_status; // Normal +} + +static inline NOR_WRITE_BLK_CHK MtdnBackupWriteRetryCount(int *count, NOR_WRITE_BLK_CHK cur_state) { + NOR_WRITE_BLK_CHK ret_state = cur_state; + (*count)++; + if (*count > BACKUP_RETRY_CNT) { + NOR_ERRLOG("retry over!! state:%d count:%d", ret_state, *count); + ret_state = RET_WT_DEV_ERR; + } + return ret_state; +} + +/*************************************************************************** +@brief MtdnBackupWriteSub +@outline Writing of specified block ID +@type Completion return type +@param[in] const char * path_name : (/dev/mtd Device) +@param[in] int i_id : ID...0~ +@param[in] int i_offset : ( i_offset >= 0) +@param[in] int i_size : ( i_size > 0) +@param[in] void *p_buff : (p_buff != NULL) +@param[in] mtd_info_t * mtd_info : info +@return NOR_WRITE_BLK_CHK +@retval RET_WT_CHK_OK : No error +@retval Except : Error +@usage It is Backup API of data read. +*****************************************************************************/ +NOR_WRITE_BLK_CHK MtdnBackupWriteSub(const char * path_name, int i_id, int i_offset, + int i_size, void *p_buff, mtd_info_t * mtd_info) { + NOR_WRITE_BLK_CHK ret_status = RET_WT_CHK_OK; + char* lp_buffer; + + lp_buffer = (char *)malloc(mtd_info->erasesize); + if (lp_buffer == NULL) { + NOR_ERRLOG("malloc:%p", lp_buffer); + ret_status = RET_WT_DEV_ERR; // error + } else { + memset(lp_buffer, 0x00, mtd_info->erasesize); + NOR_W_STATE cycle_state = NOR_IDEL; + int retry_cnt = 0; + int get_state = 0; // Read status + + while ((cycle_state < NOR_WRITE_END) + &&(ret_status == RET_WT_CHK_OK)) { + switch (cycle_state) { + case NOR_IDEL: // IDLE + if (RET_RD_CHK_OK != MtdnBackupReadSub((const char *)path_name, i_id, 0, + (int)mtd_info->erasesize, lp_buffer, mtd_info, &get_state)) { + cycle_state = NOR_READ_ERR; // read error + } else { + // write data set + memcpy(&lp_buffer[i_offset], p_buff, (size_t)i_size); + if (get_state == 0) { + cycle_state = NOR_ORG_READ; // Org read Normal + } else { + // Bakread Normal + cycle_state = NOR_BACK_READ; + } + // Embedding of write-in data + memcpy(&lp_buffer[i_offset], p_buff, (size_t)i_size); + } + break; + case NOR_READ_ERR: // read error + memset((char *)lp_buffer, 0x00, mtd_info->erasesize); + // Embedding of write-in data + memcpy(&lp_buffer[i_offset], p_buff, (size_t)i_size); + cycle_state = NOR_ORG_READ; // Org read Normal + break; + case NOR_ORG_READ: // Orgread Normal + // LCOV_EXCL_BR_START 6: double check + if (0 != MtdBackupCheksumWrite(lp_buffer, (int)mtd_info->erasesize )) { // check SUM + // LCOV_EXCL_BR_STOP + // error(It does not generate.) + AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert + ret_status = RET_WT_DEV_ERR; // LCOV_EXCL_LINE 8: dead code + } else { + // data write + if (0 == MtdnBackupWriteBase((const char *)path_name, (i_id+1), 0, + (int)mtd_info->erasesize, lp_buffer, mtd_info)) { + cycle_state = NOR_BAK_WRT; // Bakwrite Success + retry_cnt = 0; + } else { + ret_status = MtdnBackupWriteRetryCount(&retry_cnt, ret_status); + } + } + break; + case NOR_BAK_WRT: // BakWriteSuccess + // Data write + // LCOV_EXCL_BR_START 11:unexpected branch + if (0 == MtdnBackupWriteBase((const char *)path_name, i_id, 0, + (int)mtd_info->erasesize, lp_buffer, mtd_info)) { + // LCOV_EXCL_BR_STOP + cycle_state = NOR_WRITE_END; // Normal end + } else { + // LCOV_EXCL_START 5: c API error case. + AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert + ret_status = MtdnBackupWriteRetryCount(&retry_cnt, ret_status); + // LCOV_EXCL_STOP + } + break; + case NOR_BACK_READ: // Bak read normal + // LCOV_EXCL_BR_START 6: double check + if (0 != MtdBackupCheksumWrite(lp_buffer, (int)mtd_info->erasesize )) { // check SUM + // LCOV_EXCL_BR_STOP + // Retry over + AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert + ret_status = RET_WT_DEV_ERR; // LCOV_EXCL_LINE 8: dead code + } else { + // data write + if (0 == MtdnBackupWriteBase((const char *)path_name, i_id, 0, + (int)mtd_info->erasesize, lp_buffer, mtd_info)) { + // Org write Succses + cycle_state = NOR_ORG_WRITE; + retry_cnt = 0; + } else { + // LCOV_EXCL_START 5: c API error case. + AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert + ret_status = MtdnBackupWriteRetryCount(&retry_cnt, ret_status); + // LCOV_EXCL_STOP + } + } + break; + case NOR_ORG_WRITE: // Org write Succses + // data write + if (0 == MtdnBackupWriteBase((const char *)path_name, (i_id+1), 0, + (int)mtd_info->erasesize, lp_buffer, mtd_info)) { + // Normal end + cycle_state = NOR_WRITE_END; + } else { + // LCOV_EXCL_START 5: c API error case. + AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert + ret_status = MtdnBackupWriteRetryCount(&retry_cnt, ret_status); + // LCOV_EXCL_STOP + } + break; + default: + // LCOV_EXCL_START 8: dead code + AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert + NOR_ERRLOG("invalid state:%d", cycle_state); + // other error + ret_status = RET_WT_ERR_OTHER; + break; + // LCOV_EXCL_STOP + } + } + free(lp_buffer); + } + return ret_status; // Normal +} + +/*************************************************************************** +@brief MtdnBackupReadBase +@outline Read-out of specified block ID +@type Completion return type +@param[in] const char * path_name : (/dev/mtd Device) +@param[in] int i_id : ID...0~ +@param[in] int i_offset : ( i_offset >= 0) +@param[in] int i_size : ( i_size > 0) +@param[in] void *p_buff : (p_buff != NULL) +@param[in] mtd_info_t * mtd_info : +@return int +@retval 0 : No error +@retval Except : Error +@usage It is Backup API of data read. +*****************************************************************************/ +int MtdnBackupReadBase(const char * path_name, int i_id, int i_offset, + int i_size, void *p_buff, mtd_info_t * mtd_info) { + int ret_status = RET_DEV_NORMAL; + + int mtd_fd = open(path_name, O_RDONLY|O_CLOEXEC); + // LCOV_EXCL_BR_START 5:It's impossible to mock open() function,so this line can not be passed. + if (mtd_fd == -1) { + // LCOV_EXCL_BR_STOP + // LCOV_EXCL_START 5:It's impossible to mock open() function,so this line can not be passed. + AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert + NOR_ERRLOG("open(%s):%s", path_name, strerror(errno)); + ret_status = RET_DEV_ERROR; + // LCOV_EXCL_STOP + } else { + int seek_top = i_id * (int)mtd_info->erasesize + i_offset; + int sector_size = BACKUP_SECTOR_SIZ; + int block_size = (int)mtd_info->erasesize / sector_size; // Division number + int llpi; + int buff_top = 0; + int get_size = i_size; + char * work_buff = (char *)p_buff; + ssize_t read_size; + + // It reads several sector minutes. + for (llpi=0; llpi < block_size; llpi++) { // LCOV_EXCL_BR_LINE 11:unexpected branch + // It moves to a head. + if (-1 == (off_t)lseek(mtd_fd, seek_top, SEEK_SET)) { + NOR_ERRLOG("lseek():%s", strerror(errno)); + ret_status = RET_DEV_ERROR; + break; + } + if (get_size >= sector_size) { // LCOV_EXCL_BR_LINE 6:double check + read_size = read(mtd_fd, &work_buff[buff_top], (size_t)sector_size); + if (read_size < 0) { + NOR_ERRLOG("read():%zd %s", read_size, strerror(errno)); + ret_status = RET_DEV_ERROR; + break; + } + + get_size -= sector_size; + if (get_size <= 0) { + break; + } + } else { + // LCOV_EXCL_START 8: dead code + AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert + read_size = read(mtd_fd, &work_buff[buff_top], (size_t)get_size); + if (read_size < 0) { + NOR_ERRLOG("read():%zd %s", read_size, strerror(errno)); + ret_status = RET_DEV_ERROR; + break; + } + break; + // LCOV_EXCL_STOP + } + seek_top += (int)read_size; + buff_top += (int)read_size; + } + // LCOV_EXCL_BR_START 5:It's impossible to mock close() function,so this line can not be passed. + if (0 != close(mtd_fd)) { + // LCOV_EXCL_BR_STOP + // LCOV_EXCL_START 5:It's impossible to mock close() function,so this line can not be passed. + AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert + NOR_ERRLOG("close():%s", strerror(errno)); + ret_status = RET_DEV_ERROR; + // LCOV_EXCL_STOP + } + } + return ret_status; +} + +/*************************************************************************** +@brief MtdnBackupWriteBase +@outline Writing of specified block ID +@type Completion return type +@param[in] const char * path_name : (/dev/mtd Device) +@param[in] int i_id : ID...0~ +@param[in] int i_offset : ( i_offset >= 0) +@param[in] int i_size : ( i_size > 0) +@param[in] void *p_buff : (p_buff != NULL) +@param[in] mtd_info_t * mtd_info : +@return int +@retval 0 : No error +@retval Except : Error +@usage It is Backup API of data read. +*****************************************************************************/ +int MtdnBackupWriteBase(const char * path_name, int i_id, int i_offset, + int i_size, void *p_buff, mtd_info_t * mtd_info) { + int ret_status = RET_DEV_NORMAL; + + int mtd_fd = open(path_name, O_RDWR|O_CLOEXEC); + if (mtd_fd == -1) { + NOR_ERRLOG("open(%s):%s", path_name, strerror(errno)); + ret_status = RET_DEV_ERROR; + } else { + erase_info_t s_mtd_erase; + s_mtd_erase.start = (__u32)i_id * mtd_info->erasesize; + s_mtd_erase.length = mtd_info->erasesize; + // erase + if (ioctl(mtd_fd, MEMERASE, &s_mtd_erase) < 0) { + NOR_ERRLOG("ioctl(MEMERASE):%s", strerror(errno)); + ret_status = RET_DEV_ERROR; + } else { + // write + int seek_top = i_id * (int)mtd_info->erasesize + i_offset; + int sector_size = BACKUP_SECTOR_SIZ; // + int block_size = (int)mtd_info->erasesize/sector_size; + int llpi; + int buff_top = 0; + int put_size = i_size; + char * work_buff = (char *)p_buff; + ssize_t write_size; + + for (llpi=0; llpi < block_size; llpi++) { // LCOV_EXCL_BR_LINE 11:unexpected branch + if (-1 == (off_t)lseek(mtd_fd, seek_top, SEEK_SET)) { + NOR_ERRLOG("lseek():%s", strerror(errno)); + ret_status = RET_DEV_ERROR; + break; + } + if (put_size >= sector_size) { // LCOV_EXCL_BR_LINE 6:double check + write_size = write(mtd_fd, &work_buff[buff_top], (size_t)sector_size); + if (write_size < 0) { + NOR_ERRLOG("write():%zd %s", write_size, strerror(errno)); + ret_status = RET_DEV_ERROR; + break; + } + put_size -= sector_size; + if (put_size <= 0) { + break; + } + } else { + // LCOV_EXCL_START 8: dead code + AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert + write_size = write(mtd_fd, &work_buff[buff_top], (size_t)put_size); + if (write_size < 0) { + NOR_ERRLOG("write():%zd %s", write_size, strerror(errno)); + ret_status = RET_DEV_ERROR; + break; + } + break; + // LCOV_EXCL_STOP + } + seek_top += (int)write_size; + buff_top += (int)write_size; + } + } + // LCOV_EXCL_BR_START 5:It's impossible to mock close() function,so this line can not be passed. + if (0 != close(mtd_fd)) { + // LCOV_EXCL_BR_STOP + // LCOV_EXCL_START 5:It's impossible to mock close() function,so this line can not be passed. + AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert + NOR_ERRLOG("close():%s", strerror(errno)); + ret_status = RET_DEV_ERROR; + // LCOV_EXCL_STOP + } + } + return ret_status; +} + +/*************************************************************************** +int backup_cheksum_read(char * p_buff, int erase_size ,int * ret_sum) + * A text character sequence and a sum value are checked. + IN: char * p_buff ...top address + int erase_size ...erase size + int * ret_sum ...return sum + + OUT: NOR_BLK_CHK RET_CHK_OK:Normal + RET_CHK_TEXT_ERR:test error + RET_CHK_BCC_ERR:sum error Except:other error + Remarks: +*****************************************************************************/ +NOR_BLK_CHK MtdBackupCheksumRead(char * p_buff, int erase_size, int * ret_sum) { + if (erase_size > BACKUP_CHECK_OFFSET) { // LCOV_EXCL_BR_LINE 6: double check + // The check of the compatibility of block data + if (0 != memcmp(&p_buff[(erase_size-BACKUP_CHECK_OFFSET)], BACKUP_CHECK_TEXT, BACKUP_CHECK_SIZE)) { + char tmp[BACKUP_CHECK_SIZE + 1]; + memcpy(tmp, &p_buff[(erase_size-BACKUP_CHECK_OFFSET)], BACKUP_CHECK_SIZE); + tmp[BACKUP_CHECK_SIZE] = '\0'; + NOR_ERRLOG("invalid check_text:%s", tmp); + return RET_CHK_TEXT_ERR; + } + // The check of the compatibility of block data + int llpi; + int get_sum; + int work_sum = 0; + get_sum = ((int)p_buff[(erase_size-BACKUP_CHECK_DAT2)] & 0xff) + + (((int)p_buff[(erase_size-BACKUP_CHECK_DAT1)]) << 8 & 0xff00); + + for (llpi=0; llpi < (erase_size-BACKUP_CHECK_OFFSET); llpi++) { + work_sum += p_buff[llpi]; + } + work_sum = (work_sum & 0xffff); + if (work_sum != get_sum) { + NOR_ERRLOG("invalid checksum: work:%d get:%d", work_sum, get_sum); + return RET_CHK_BCC_ERR; // checksum error + } + if (ret_sum != NULL) { // LCOV_EXCL_BR_LINE 6: double check + *ret_sum = work_sum; // chesum Storing + } + } else { + // LCOV_EXCL_START 8: dead code + AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert + NOR_ERRLOG("invalid erase_size:%d", erase_size); + // checksum error + return RET_CHK_BCC_ERR; + // LCOV_EXCL_STOP + } + return RET_CHK_OK; +} + +/*************************************************************************** +int backup_cheksum_write(char * p_buff, int erase_size ) + * A text character sequence and a sum value are written in a buffer. + IN: char * p_buff ...top address + int erase_size ...erase size + + OUT: int 0:normal Except:error + Remarks: +*****************************************************************************/ +int MtdBackupCheksumWrite(char * p_buff, int erase_size ) { + int sum_add = 0; + + if (erase_size > BACKUP_CHECK_OFFSET) { // LCOV_EXCL_BR_LINE 11:unexpected branch + int ret_status; + // The check of the compatibility of block data + ret_status = memcmp(&p_buff[(erase_size-BACKUP_CHECK_OFFSET)], BACKUP_CHECK_TEXT, BACKUP_CHECK_SIZE); + if (ret_status != 0) { + memcpy(&p_buff[(erase_size-BACKUP_CHECK_OFFSET)], BACKUP_CHECK_TEXT, BACKUP_CHECK_SIZE); + } + int llpi; + for (llpi=0; llpi < (erase_size-BACKUP_CHECK_OFFSET); llpi++) { + sum_add += p_buff[llpi]; + } + } + p_buff[(erase_size-BACKUP_CHECK_DAT2)] = (char)(sum_add & 0xff); + p_buff[(erase_size-BACKUP_CHECK_DAT1)] = (char)((sum_add>>8) & 0xff); + return RET_DEV_NORMAL; +} + +/*************************************************************************** +@brief MtdBackupInfo( mtd_info_t * mtd_info) +@outline The information to obtain is obtained. +@type Completion return type +@param[in] mtd_info_t * mtd_info +@return int +@retval 0 : No error +@retval Except : Error +@usage It is Backup API of data read. +*****************************************************************************/ +int MtdBackupInfo(const char * path_name, mtd_info_t * mtd_info) { + int ret_status = RET_DEV_NORMAL; + + int mtd_fd = open(path_name, O_RDONLY|O_CLOEXEC); + if (mtd_fd == -1) { + NOR_ERRLOG("open(%s):%s", path_name, strerror(errno)); + ret_status = RET_DEV_ERROR; + } else { + // device control mtdchar_ioctl of mtdchar.c + if (ioctl(mtd_fd, MEMGETINFO, mtd_info) < 0) { + NOR_ERRLOG("ioctl(MEMGETINFO):%s", strerror(errno)); + ret_status = RET_DEV_ERROR; + } + if (0 != close(mtd_fd)) { + NOR_ERRLOG("close():%s", strerror(errno)); + ret_status = RET_DEV_ERROR; + } + } + return ret_status; +} + +/************************************************************** + End Of Files +**************************************************************/