#include "HFlashServer.h" #include "HDLog.h" #include "HTimer.h" #if HFLASH_USE_HSHELL #include "HShellLex.h" #endif #include #ifdef HFLASH_USE_FLASH_MEM #include "HFlashMem.h" #endif #ifndef USE_STD_MEM #ifndef HFLASH_USE_FLASH_MEM #include "HDSendBuffer.h" #endif // HFLASH_USE_FLASH_MEM #include "HSCrc32.h" #endif #if !HFLASH_USE_BITMAP #include "HVector.h" #endif #ifdef USE_STD_MEM #include static uint32_t sCrcValue; void HSCrc32Reset() { sCrcValue = 0xFFFFFFFF; } void HSCrc32Update(const uint8_t *data, size_t len) { for (size_t i = 0; i < len; i++) { sCrcValue = _mm_crc32_u8(sCrcValue, data[i]); } } uint32_t HSCrc32Get() { return sCrcValue ^ 0xFFFFFFFF; } #endif // 计算最小值 #define FAST_MIN(type, a, b) ((b) ^ (((a) ^ (b)) & (-(type)((a) < (b))))) #ifdef USE_FATAL_NOT_LOOP #define FATAL_ERROR(format, ...) LogE(format, ##__VA_ARGS__); #else __attribute__((weak)) void HDMainLoopCallOverride(uint8_t event) { (void)(event); #if HFLASH_USE_HSHELL HShellRun(); #endif } #define FATAL_ERROR(format, ...) while (1) { LogE(format, ##__VA_ARGS__); HDMainLoopCallOverride(0); }; #endif // 最大热度 #define MAX_HEAT ((1 << 4) - 1) // 检查是不是4对齐 #define IS_NOT_4(size) ((size & (4 - 1)) != 0) #define IS_NOT_4K(size) ((size & (HFLASH_BLOCK_SIZE - 1)) != 0) #define ALIGN_4K(size) (((size) + HFLASH_BLOCK_SIZE - 1) & ~(HFLASH_BLOCK_SIZE - 1)) // 计算bitMap地址 #define CALC_BITMAP_INDEX(addr) ((addr) >> 12) // 从bitMap计算flash偏移地址 #define CALC_FLASH_BITMAP_OFFSET(index) ((index) << 12) #if HFLASH_USE_HSHELL enum eShell { kShellPageInfo, ///< 查看页表信息 kShellDelUseDataPage, ///< 删除页表使用数据 kShellDelPage, ///< 删除页 kShellResetPage, ///< 重置页 kShellRestorePage, ///< 恢复页 #ifdef HFLASH_USE_FLASH_MEM kShellFlashMemInfo, ///< 查看flash内存信息 #endif kShellMax, }; static HShellMatch sShellMatch[] = { HSHELL_MATCH_ITEM(kShellPageInfo, "pageInfo"), HSHELL_MATCH_ITEM(kShellDelUseDataPage, "pageDelUseData"), HSHELL_MATCH_ITEM(kShellDelPage, "pageDel"), HSHELL_MATCH_ITEM(kShellResetPage, "pageReset"), HSHELL_MATCH_ITEM(kShellRestorePage, "pageRestore"), #ifdef HFLASH_USE_FLASH_MEM HSHELL_MATCH_ITEM(kShellFlashMemInfo, "flashMemInfo"), #endif }; #endif union PageInfo { uint8_t reverse[32]; ///< 每页的信息占用32字节 struct __attribute__((packed)) { uint32_t crc32; ///< 页表内容的CRC32校验值 uint32_t pageNum : 19; ///< 可用页数量 uint32_t useNum : 19; ///< 已使用页数量 }; }; struct Info { #ifndef HFLASH_USE_FLASH_MEM HFlashReadCallback read; ///< 读取回调 HFlashWriteCallback write; ///< 写入回调 HFlashEraseCallback erase; ///< 擦除回调 #endif HFlashAddr_t pageAddr; ///< 页表地址 HFlashAddr_t pageBackupAddr; ///< 页表备份地址 uint32_t pageSize; ///< 页大小 HFlashProtectInfo *protectInfo; ///< 保护区描述缓存 uint16_t protectCacheSize; ///< 保护区描述缓存大小 uint16_t protectUseNum; ///< 保护区使用数量 HFlashCacheInfo *pageCache; ///< 页表缓存 uint16_t pageCacheSize; ///< 页表缓存大小 uint16_t pageCacheUseNum; ///< 页表缓存使用页 }; static struct Info sInfo; static union PageInfo sPageInfo; // 备份定时器 static HTimer_t sBackupTimer = HTIMER_INVALID; #ifndef HFLASH_USE_FLASH_MEM // 同步页定时器 static HTimer_t sSyncPageTimer = HTIMER_INVALID; #endif // 同步页表缓存定时器 static HTimer_t sSyncCacheTimer = HTIMER_INVALID; #if !HFLASH_USE_BITMAP // 存储需要备份的保护区地址页偏移 static HVECTOR_DEFINE32(sNeedBackupOffset, 10); #endif static uint8_t RestoreBackup(HFlashAddr_t srcAddr, HFlashAddr_t dstAddr, uint32_t size); static uint8_t RestoreBackupRange(HFlashAddr_t addr, uint32_t size); static uint8_t SyncBackupRange(HFlashAddr_t addr, uint32_t size); static void StartSyncBackupTimer(); static uint8_t ReadFlashCall(HFlashAddr_t addr, void *data, uint32_t size); static int16_t FindProtectIndex(HFlashAddr_t addr, uint32_t size); static int16_t FindProtectBackupIndex(HFlashAddr_t addr, uint32_t size); static int16_t FindProtectAddrIndex(HFlashAddr_t addr); static HFlashCacheInfo *FindCache(HFlashAddr_t addr); static void WriteCachePage(HFlashCacheInfo *info); static uint32_t GetFlashCrc32(HFlashAddr_t addr, uint32_t size); static uint8_t ReadBackup(HFlashAddr_t addr, void *data, uint32_t size); static uint32_t GetBackupCrc32(HFlashAddr_t addr, uint32_t size); static uint8_t GetBackupAddr(HFlashAddr_t addr, uint32_t size, HFlashAddr_t *backupAddr); static uint8_t GetProtectBackupRange(HFlashAddr_t addr, uint32_t size, HFlashAddr_t *backupStartAddr, uint32_t *backupSize); static inline uint32_t AdjustProtectBackupSize(HFlashAddr_t addr, uint32_t size); static void ClearProtectInfoEntry(HFlashProtectInfo *info); static void ResetRuntimeState() { if (sBackupTimer != HTIMER_INVALID) { HTimerRemove(sBackupTimer); sBackupTimer = HTIMER_INVALID; } #ifndef HFLASH_USE_FLASH_MEM if (sSyncPageTimer != HTIMER_INVALID) { HTimerRemove(sSyncPageTimer); sSyncPageTimer = HTIMER_INVALID; } #endif if (sSyncCacheTimer != HTIMER_INVALID) { HTimerRemove(sSyncCacheTimer); sSyncCacheTimer = HTIMER_INVALID; } #if HFLASH_USE_BITMAP for (uint16_t i = 0; i < sInfo.protectCacheSize; ++i) { if (sInfo.protectInfo[i].bitMap) { HBitMapFill(sInfo.protectInfo[i].bitMap, 0); } } #else HVectorClear(sNeedBackupOffset); #endif } ///< 检查地址是否在双备份保护区内 static uint8_t IsProtect(HFlashAddr_t addr, uint32_t size) { return FindProtectIndex(addr, size) >= 0; } static uint8_t GetProtectBackupRange(HFlashAddr_t addr, uint32_t size, HFlashAddr_t *backupStartAddr, uint32_t *backupSize) { const uint64_t startAddr = addr & ~((uint64_t)HFLASH_BLOCK_SIZE - 1u); const uint64_t endAddr = (uint64_t)addr + size; const uint64_t alignMask = (uint64_t)HFLASH_BLOCK_SIZE - 1u; uint64_t backupEnd = endAddr; if (size == 0) { *backupStartAddr = (HFlashAddr_t)startAddr; *backupSize = 0; return 1; } if (endAddr > UINT32_MAX) { FATAL_ERROR("protect addr[0x%08x] size[%d] overflow", addr, size); return 0; } if ((backupEnd & alignMask) != 0) { backupEnd = (backupEnd + alignMask) & ~alignMask; } if (backupEnd > UINT32_MAX) { FATAL_ERROR("protect addr[0x%08x] size[%d] align overflow", addr, size); return 0; } *backupStartAddr = (HFlashAddr_t)startAddr; *backupSize = (uint32_t)(backupEnd - startAddr); return 1; } static int16_t FindProtectIndexByRange(HFlashAddr_t addr, uint32_t size, uint8_t useBackupRange) { const HFlashAddr_t addrEnd = addr + size; if (addrEnd < addr) { FATAL_ERROR("addr[0x%08x] size[%d] overflow", addr, size); return -1; } for (uint16_t i = 0; i < sInfo.protectUseNum; ++i) { HFlashAddr_t protectAddr = sInfo.protectInfo[i].addr; uint32_t protectSize = sInfo.protectInfo[i].size; if (useBackupRange && GetProtectBackupRange(protectAddr, protectSize, &protectAddr, &protectSize) == 0) { return -1; } const HFlashAddr_t protectEnd = protectAddr + protectSize; if (protectEnd < protectAddr) { FATAL_ERROR("protect addr[0x%08x] size[%d] overflow", protectAddr, protectSize); return -1; } if (addr < protectAddr || addr >= protectEnd) { continue; } if (addrEnd > protectEnd) { FATAL_ERROR("addr[0x%08x][0x%08x] size[%d][%d] overflow protect%s", addr, protectAddr, size, protectSize, useBackupRange ? " backup" : ""); return -1; } return (int16_t)i; } return -1; } static int16_t FindProtectIndex(HFlashAddr_t addr, uint32_t size) { return FindProtectIndexByRange(addr, size, 0); } static int16_t FindProtectBackupIndex(HFlashAddr_t addr, uint32_t size) { return FindProtectIndexByRange(addr, size, 1); } static int16_t FindProtectAddrIndex(HFlashAddr_t addr) { for (uint16_t i = 0; i < sInfo.protectUseNum; ++i) { if (sInfo.protectInfo[i].addr == addr) { return (int16_t)i; } } return -1; } static uint8_t GetBackupAddr(HFlashAddr_t addr, uint32_t size, HFlashAddr_t *backupAddr) { const HFlashAddr_t addrEnd = addr + size; if (addrEnd < addr) { FATAL_ERROR("backup addr[0x%08x] size[%d] overflow", addr, size); return 0; } const HFlashAddr_t pageEnd = sInfo.pageAddr + sInfo.pageSize; if (pageEnd >= sInfo.pageAddr && addr >= sInfo.pageAddr && addrEnd <= pageEnd) { *backupAddr = sInfo.pageBackupAddr + (addr - sInfo.pageAddr); return 1; } const int16_t index = FindProtectBackupIndex(addr, size); if (index >= 0) { HFlashProtectInfo *info = &sInfo.protectInfo[index]; HFlashAddr_t protectAddr = 0; uint32_t protectSize = 0; if (GetProtectBackupRange(info->addr, info->size, &protectAddr, &protectSize) == 0) { return 0; } (void)protectSize; *backupAddr = info->backupAddr + (addr - protectAddr); return 1; } return 0; } static uint8_t ReadBackup(HFlashAddr_t addr, void *data, uint32_t size) { if (size == 0) { return 1; } if (data == NULL) { return 0; } HFlashAddr_t backupAddr = 0; if (GetBackupAddr(addr, size, &backupAddr) == 0) { LogE("backup addr[0x%08x] not config", addr); return 0; } return ReadFlashCall(backupAddr, data, size); } static uint8_t ReadFlashCall(HFlashAddr_t addr, void *data, uint32_t size) { if (size == 0) { return 1; } #ifdef HFLASH_USE_FLASH_MEM return HFlashMemRead(addr, data, size); #else if (sInfo.read == NULL) { FATAL_ERROR("read is null"); return 0; } return sInfo.read(addr, data, size); #endif } #ifndef HFLASH_USE_FLASH_MEM static uint8_t EraseFlashCall(HFlashAddr_t addr) { if (sInfo.erase == NULL) { FATAL_ERROR("erase is null"); return 0; } return sInfo.erase(addr); } static uint8_t WriteFlashCall(HFlashAddr_t addr, const void *data, uint32_t size) { if (size == 0) { return 1; } if (sInfo.write == NULL) { FATAL_ERROR("write is null"); return 0; } return sInfo.write(addr, data, size); } #endif #ifndef HFLASH_USE_FLASH_MEM /** * @brief 写入数据到Flash * @param addr 写入的Flash地址 * @param data 写入的数据 * @param size 写入的数据大小 * @param call 拷贝回调, dest缓存, src已经调整好位置的指针, buffSize需要拷贝的数据大小, userData用户数据 * @return 写入是否成功 */ static uint8_t WriteData(HFlashAddr_t addr, const void *data, uint32_t size, void(*call)(void *dest, const void *src, uint16_t buffSize, void *userData), void *userData) { uint8_t *dataPtr = (uint8_t *)data; uint32_t adjustAddr = addr & ~(HFLASH_BLOCK_SIZE - 1); const uint16_t offset = addr - adjustAddr; uint32_t remain = offset + size > HFLASH_BLOCK_SIZE ? HFLASH_BLOCK_SIZE - offset : size; uint8_t *buff = (uint8_t *)HFLASH_MALLOC(HFLASH_BLOCK_SIZE); uint8_t result = 0; if (buff == NULL) { LogE("addr[0x%08x], write size[%d] malloc faild", addr, size); return 0; } // 先写入首个未对齐的块 if (ReadFlashCall(adjustAddr, buff, HFLASH_BLOCK_SIZE) == 0) { LogE("addr[0x%08x], read faild", adjustAddr); goto _flashError; } if (EraseFlashCall(adjustAddr) == 0) { LogE("addr[0x%08x], erase faild", adjustAddr); goto _flashError; } call(buff + offset, dataPtr, remain, userData); if (WriteFlashCall(adjustAddr, buff, HFLASH_BLOCK_SIZE) == 0) { LogE("addr[0x%08x], write faild", adjustAddr); goto _flashError; } // 操作块读写 size -= remain; adjustAddr += HFLASH_BLOCK_SIZE; dataPtr += remain; for (; size >= HFLASH_BLOCK_SIZE; adjustAddr += HFLASH_BLOCK_SIZE, size -= HFLASH_BLOCK_SIZE, dataPtr += HFLASH_BLOCK_SIZE) { if (EraseFlashCall(adjustAddr) == 0) { LogE("addr[0x%08x], erase faild", adjustAddr); goto _flashError; } call(buff, dataPtr, HFLASH_BLOCK_SIZE, userData); if (WriteFlashCall(adjustAddr, buff, HFLASH_BLOCK_SIZE) == 0) { LogE("addr[0x%08x], write faild", adjustAddr); goto _flashError; } } // 操作最后一个未对齐的块 if (size) { if (ReadFlashCall(adjustAddr, buff, HFLASH_BLOCK_SIZE) == 0) { LogE("addr[0x%08x], read faild", adjustAddr); goto _flashError; } if (EraseFlashCall(adjustAddr) == 0) { LogE("addr[0x%08x], erase faild", adjustAddr); goto _flashError; } call(buff, dataPtr, size, userData); if (WriteFlashCall(adjustAddr, buff, HFLASH_BLOCK_SIZE) == 0) { LogE("addr[0x%08x], write faild", adjustAddr); goto _flashError; } } result = 1; _flashError: HFLASH_FREE(buff); return result; } #endif #ifndef HFLASH_USE_FLASH_MEM static void _WriteFlashHelper(void *dest, const void *src, uint16_t buffSize, void *userData) { (void)userData; memcpy(dest, src, buffSize); } #endif static uint8_t WriteFlash(HFlashAddr_t addr, const void *data, uint32_t size) { #ifdef HFLASH_USE_FLASH_MEM return HFlashMemWrite(addr, data, size); #else return WriteData(addr, data, size, _WriteFlashHelper, NULL); #endif } #ifndef HFLASH_USE_FLASH_MEM static void _WriteFalshValueHelper(void *dest, const void *src, uint16_t size, void *userData) { uint8_t *value = (uint8_t *)userData; memset(dest, *value, size); } #endif static uint8_t WriteFlashValue(uint32_t addr, uint32_t size, uint8_t value) { #ifdef HFLASH_USE_FLASH_MEM return HFlashMemSetValue(addr, value, size); #else return WriteData(addr, NULL, size, _WriteFalshValueHelper, &value); #endif } static inline uint32_t AdjustPageAddr(uint32_t addr) { return addr + sizeof(sPageInfo); } static inline uint32_t AdjustPageAddrOffset(uint32_t addr, uint32_t offset) { return addr + sizeof(sPageInfo) + offset * sizeof(HFlashPageInfo); } static inline uint32_t AdjustPageByte(uint32_t index) { return index * sizeof(HFlashPageInfo); } static inline uint32_t AdjustProtectBackupSize(HFlashAddr_t addr, uint32_t size) { HFlashAddr_t backupStartAddr = 0; uint32_t backupSize = 0; if (GetProtectBackupRange(addr, size, &backupStartAddr, &backupSize) == 0) { return 0; } (void)backupStartAddr; return backupSize; } static void ClearProtectInfoEntry(HFlashProtectInfo *info) { #if HFLASH_USE_BITMAP HBitMapType *bitMap = info->bitMap; memset(info, 0, sizeof(HFlashProtectInfo)); info->bitMap = bitMap; if (bitMap != NULL) { HBitMapFill(bitMap, 0); } #else memset(info, 0, sizeof(HFlashProtectInfo)); #endif } static void SyncBackup() { LogD("Start sync Backup"); if (sBackupTimer != HTIMER_INVALID) { HTimerRemove(sBackupTimer); sBackupTimer = HTIMER_INVALID; } #if HFLASH_USE_BITMAP for (uint16_t i = 0; i < sInfo.protectUseNum; ++i) { HFlashAddr_t protectStartAddr = 0; uint32_t backupSize = 0; if (GetProtectBackupRange(sInfo.protectInfo[i].addr, sInfo.protectInfo[i].size, &protectStartAddr, &backupSize) == 0) { return ; } (void)backupSize; HBitMapIndexType index = 0; for (;;) { index = HBitMapFindFirstSetBitIndex(sInfo.protectInfo[i].bitMap, index); if (index == kHBitMapInvalidIndex) { break; } const uint32_t addr = protectStartAddr + CALC_FLASH_BITMAP_OFFSET(index); if (SyncBackupRange(addr, HFLASH_BLOCK_SIZE) == 0) { LogE("RestorePage faild, addr[0x%08x]", addr); StartSyncBackupTimer(); return ; } HBitMapSetBit(sInfo.protectInfo[i].bitMap, index, 0); ++index; } } #else for (HVectorLenType remain = HVectorGetUseLen(sNeedBackupOffset); remain > 0; --remain) { const uint32_t addr = HVectorGetData(sNeedBackupOffset, remain - 1); if (SyncBackupRange(addr, HFLASH_BLOCK_SIZE) == 0) { LogE("RestorePage faild, addr[0x%08x]", addr); StartSyncBackupTimer(); return ; } HVectorSetUseLen(sNeedBackupOffset, remain - 1); } #endif // 备份页表数据 const uint32_t crcValue = GetBackupCrc32(AdjustPageAddr(sInfo.pageAddr), AdjustPageByte(sPageInfo.useNum)); if (crcValue != sPageInfo.crc32) { SyncBackupRange(sInfo.pageAddr, AdjustPageByte(sPageInfo.useNum + 1)); } LogD("Sync Backup End"); } static void StartSyncBackupTimer() { if (sBackupTimer != HTIMER_INVALID) { HTimerRemove(sBackupTimer); sBackupTimer = HTIMER_INVALID; } sBackupTimer = HTimerAdd(HFLASH_TIMER_ID, HFLASH_SYNC_BACKUP_TIME, SyncBackup, kHTimerOnce); } static void _AddBackupAddr(uint32_t addr, int16_t protecIndex) { #if HFLASH_USE_BITMAP HFlashAddr_t protectStartAddr = 0; uint32_t backupSize = 0; HFlashProtectInfo *info = &sInfo.protectInfo[protecIndex]; if (GetProtectBackupRange(info->addr, info->size, &protectStartAddr, &backupSize) == 0) { return ; } if (addr < protectStartAddr || addr >= (protectStartAddr + backupSize)) { LogE("protect bitmap addr[0x%08x] out of range[0x%08x][0x%08x]", addr, protectStartAddr, protectStartAddr + backupSize); return ; } HBitMapSetBit(info->bitMap, (addr - protectStartAddr) >> 12, 1); LogD("Add wait sync addr[0x%08x]", addr); #else do { const HVectorLenType index = HVectorFindData(sNeedBackupOffset, addr); if (index != HVECTOR_ERROR) { break; } if (HVectorAddData(sNeedBackupOffset, addr)) { break; } // 添加数据失败, 缓存已满, 需要先同步再添加 SyncBackup(); if (HVectorAddData(sNeedBackupOffset, addr) == 0) { LogE("add wait sync addr[0x%08x], faild", addr); break; } } while (0); LogD("Add wait sync addr[0x%08x], size[%d]", addr, HVectorGetUseLen(sNeedBackupOffset)); #endif StartSyncBackupTimer(); } static void AddBackupAddr(uint32_t addr, uint32_t size) { int16_t protectIndex = FindProtectIndex(addr, size); if (protectIndex < 0) { return ; } // 只需要存储对应页位置, 整个页拷贝, 需要判断是不是需要超越页边界 uint32_t adjustAddr = addr & ~(HFLASH_BLOCK_SIZE - 1); const uint16_t offset = addr - adjustAddr; uint32_t remain = offset + size > HFLASH_BLOCK_SIZE ? HFLASH_BLOCK_SIZE - offset : size; _AddBackupAddr(adjustAddr, protectIndex); size -= remain; adjustAddr += HFLASH_BLOCK_SIZE; for (; size >= HFLASH_BLOCK_SIZE; adjustAddr += HFLASH_BLOCK_SIZE, size -= HFLASH_BLOCK_SIZE) { _AddBackupAddr(adjustAddr, protectIndex); } if (size) { _AddBackupAddr(adjustAddr, protectIndex); } } static void AddBackupOffsetAddr(uint32_t addr, uint32_t offset, uint32_t size) { AddBackupAddr(addr + offset, size); } static uint8_t _CalcCrc32(uint32_t addr, uint32_t offset, const uint8_t *data, uint16_t len, void *args) { uint32_t needLen = *(uint32_t *)args; uint32_t calcLen = FAST_MIN(uint32_t, (needLen - offset), len); HSCrc32Update(data, calcLen); return needLen <= offset + len; } static uint32_t GetFlashCrc32(HFlashAddr_t addr, uint32_t size) { if (size == 0) { return 0xFFFFFFFF; } HSCrc32Reset(); #ifdef HFLASH_USE_FLASH_MEM if (HFlashMemMMapCall(addr, _CalcCrc32, &size) == 0) { LogE("addr[0x%08x], size[%d] mmap faild", addr, size); return 0xFFFFFFFF; } #else uint8_t *buff = (uint8_t *)HFLASH_MALLOC(HFLASH_BLOCK_SIZE); if (buff == NULL) { LogE("addr[0x%08x], write size[%d] malloc faild", addr, size); return 0xFFFFFFFF; } for (uint32_t i = 0; i < size; i += HFLASH_BLOCK_SIZE) { const uint32_t remain = FAST_MIN(uint32_t, size - i, HFLASH_BLOCK_SIZE); if (ReadFlashCall(addr + i, buff, remain) == 0) { LogE("addr[0x%08x][0x%08x], size[%d] read faild", addr, addr + i, remain); break; } HSCrc32Update(buff, remain); } HFLASH_FREE(buff); #endif return HSCrc32Get(); } static uint32_t GetBackupCrc32(HFlashAddr_t addr, uint32_t size) { if (size == 0) { return 0xFFFFFFFF; } HFlashAddr_t backupAddr = 0; if (GetBackupAddr(addr, size, &backupAddr) == 0) { LogE("backup addr[0x%08x] not config", addr); return 0xFFFFFFFF; } return GetFlashCrc32(backupAddr, size); } static uint8_t RestoreBackup(HFlashAddr_t srcAddr, HFlashAddr_t dstAddr, uint32_t copySize) { if (copySize == 0) { LogD("addr[0x%08x], write size[%d] is 0", srcAddr, copySize); return 1; } #ifdef HFLASH_USE_FLASH_MEM return HFlashMemAddrCopy(srcAddr, dstAddr, copySize); #else uint8_t *buff = (uint8_t *)HFLASH_MALLOC(HFLASH_BLOCK_SIZE); if (buff == NULL) { LogE("addr[0x%08x], write size[%d] malloc faild", srcAddr, copySize); return 0; } uint8_t result = 0; uint32_t adjustAddr = dstAddr & ~(HFLASH_BLOCK_SIZE - 1); uint32_t size = copySize; uint32_t srcOffset = 0; // 如果地址不是对齐页的, 先处理残余数据到对齐页 if (adjustAddr != dstAddr) { const uint16_t offset = dstAddr - adjustAddr; const uint32_t remain = offset + size > HFLASH_BLOCK_SIZE ? HFLASH_BLOCK_SIZE - offset : size; // 先读取到对齐页, 然后将未对齐的数据重写 result = ReadFlashCall(adjustAddr, buff, HFLASH_BLOCK_SIZE) == 0; result = result || ReadFlashCall(srcAddr + srcOffset, buff + offset, remain) == 0; result = result || EraseFlashCall(adjustAddr) == 0; result = result || WriteFlashCall(adjustAddr, buff, HFLASH_BLOCK_SIZE) == 0; if (result) { result = 0; LogE("addr[0x%08x], write size[%d] faild", srcAddr, size); goto _FlashError; } size -= remain; adjustAddr += HFLASH_BLOCK_SIZE; srcOffset += remain; } // 中间对齐页直接读原地址页, 擦写目标页 for (; size >= HFLASH_BLOCK_SIZE; adjustAddr += HFLASH_BLOCK_SIZE, size -= HFLASH_BLOCK_SIZE, srcOffset += HFLASH_BLOCK_SIZE) { result = result || ReadFlashCall(srcAddr + srcOffset, buff, HFLASH_BLOCK_SIZE) == 0; result = result || EraseFlashCall(adjustAddr) == 0; result = result || WriteFlashCall(adjustAddr, buff, HFLASH_BLOCK_SIZE) == 0; if (result) { result = 0; LogE("addr[0x%08x], write size[%d] faild", srcAddr, size); goto _FlashError; } } // 最后不对齐的数据 if (size) { result = result || ReadFlashCall(adjustAddr, buff, HFLASH_BLOCK_SIZE) == 0; result = result || ReadFlashCall(srcAddr + srcOffset, buff, size) == 0; result = result || EraseFlashCall(adjustAddr) == 0; result = result || WriteFlashCall(adjustAddr, buff, HFLASH_BLOCK_SIZE) == 0; if (result) { result = 0; LogE("addr[0x%08x], write size[%d] faild", srcAddr, size); goto _FlashError; } size = 0; } result = 1; _FlashError: HFLASH_FREE(buff); LogD("Restore srcAddr[0x%08x], dstAddr[0x%08x], size[%d][%d], result[%d]", srcAddr, dstAddr, size, copySize, result); return result; #endif } static uint8_t CopyBackupRange(HFlashAddr_t addr, uint32_t size, uint8_t isRestore) { HFlashAddr_t backupAddr = 0; if (GetBackupAddr(addr, size, &backupAddr) == 0) { LogE("backup addr[0x%08x] not config", addr); return 0; } if (isRestore) { return RestoreBackup(backupAddr, addr, size); } return RestoreBackup(addr, backupAddr, size); } static uint8_t RestoreBackupRange(HFlashAddr_t addr, uint32_t size) { return CopyBackupRange(addr, size, 1); } static uint8_t SyncBackupRange(HFlashAddr_t addr, uint32_t size) { return CopyBackupRange(addr, size, 0); } ///< 恢复指定页表 static uint8_t RestorePage(uint32_t index) { if (index >= sPageInfo.useNum) { LogE("index[%d][%d] overflow", index, sPageInfo.useNum); return 0; } return RestoreBackupRange(AdjustPageAddrOffset(sInfo.pageAddr, index), sizeof(HFlashPageInfo)); } static void SyncPageInfo() { #ifndef HFLASH_USE_FLASH_MEM if (sSyncPageTimer != HTIMER_INVALID) { HTimerRemove(sSyncPageTimer); sSyncPageTimer = HTIMER_INVALID; } #endif const uint32_t crcValue = GetFlashCrc32(AdjustPageAddr(sInfo.pageAddr), AdjustPageByte(sPageInfo.useNum)); if (crcValue == sPageInfo.crc32) { return; } sPageInfo.crc32 = crcValue;; WriteFlash(sInfo.pageAddr, &sPageInfo, sizeof(sPageInfo)); StartSyncBackupTimer(); } #ifndef HFLASH_USE_FLASH_MEM static void StartSyncPageInfo() { if (sSyncPageTimer != HTIMER_INVALID) { HTimerRemove(sSyncPageTimer); sSyncPageTimer = HTIMER_INVALID; } sSyncPageTimer = HTimerAdd(HFLASH_TIMER_ID, HFLASH_SYNC_PAGE_INFO_TIME, SyncPageInfo, kHTimerOnce); StartSyncBackupTimer(); } #endif static void ReadPage(uint32_t index, HFlashPageInfo *info) { if (index >= sPageInfo.useNum || info == NULL) { LogE("index[%d][%d] overflow", index, sPageInfo.useNum); return; } const HFlashAddr_t addr = AdjustPageAddrOffset(sInfo.pageAddr, index); ReadFlashCall(addr, info, sizeof(HFlashPageInfo)); } static void WritePage(uint32_t index, HFlashPageInfo *info) { if (index >= sPageInfo.useNum || info == NULL) { LogE("index[%d][%d] overflow", index, sPageInfo.useNum); return; } const HFlashAddr_t addr = AdjustPageAddrOffset(sInfo.pageAddr, index); WriteFlash(addr, info, sizeof(HFlashPageInfo)); #ifdef HFLASH_USE_FLASH_MEM SyncPageInfo(); #else StartSyncPageInfo(); #endif } static void SyncCachePage() { if (sSyncCacheTimer != HTIMER_INVALID) { HTimerRemove(sSyncCacheTimer); sSyncCacheTimer = HTIMER_INVALID; } for (uint32_t i = 0; i < sInfo.pageCacheUseNum; ++i) { // 更新Crc32 if (sInfo.pageCache[i].waitCrc) { sInfo.pageCache[i].waitCrc = 0; sInfo.pageCache[i].info.crc32 = GetFlashCrc32(sInfo.pageCache[i].info.addr, sInfo.pageCache[i].info.useSize); sInfo.pageCache[i].waitWrite = 1; } // 写入页表 if (sInfo.pageCache[i].waitWrite) { WritePage(sInfo.pageCache[i].pos, &sInfo.pageCache[i].info); } } #ifdef HFLASH_USE_FLASH_MEM SyncPageInfo(); #else StartSyncPageInfo(); #endif } static void StartSyncCachePage() { if (sSyncCacheTimer != HTIMER_INVALID) { HTimerRemove(sSyncCacheTimer); sSyncCacheTimer = HTIMER_INVALID; } sSyncCacheTimer = HTimerAdd(HFLASH_TIMER_ID, HFLASH_SYNC_CACHE_PAGE_TIME, SyncCachePage, kHTimerOnce); #ifndef HFLASH_USE_FLASH_MEM StartSyncPageInfo(); #endif } static void WriteCachePage(HFlashCacheInfo *info) { ++info->info.modifyCount; info->waitWrite = 1; #ifdef HFLASH_USE_FLASH_MEM // 如果是延迟CRC的, 不需要立刻同步, 避免还在不断写 if (info->waitCrc) { StartSyncCachePage(); return ; } SyncCachePage(); SyncPageInfo(); #else StartSyncCachePage(); #endif } /// 检查是否重叠, 重叠返回1, 非重叠返回0 static uint8_t IsOverLap(HFlashAddr_t srcAddr, uint32_t size, HFlashAddr_t dstAddr, uint32_t dstSize) { if (size == 0 || dstSize == 0) { return 0; } const HFlashAddr_t srcEnd = srcAddr + size; const HFlashAddr_t dstEnd = dstAddr + dstSize; if (srcEnd < srcAddr) { FATAL_ERROR("addr[0x%08x] size[%d] overflow", srcAddr, size); return 1; } if (dstEnd < dstAddr) { FATAL_ERROR("addr[0x%08x] size[%d] overflow", dstAddr, dstSize); return 1; } if (srcAddr == dstAddr) { FATAL_ERROR("addr[0x%08x] dstAddr[%d] overflow", srcAddr, dstAddr); return 1; } // 非重叠 if (srcEnd <= dstAddr || dstEnd <= srcAddr) { return 0; } return 1; } /** * @brief 扫描页表 * @param call 回调函数, index 页表索引, info 页表信息, userData 用户数据, 返回0继续扫描 * @param userData 用户数据 * @return uint8_t 结束0, 否则返回用户回调函数返回值 */ static uint8_t ScanPage(uint8_t (*call)(uint32_t index, HFlashPageInfo *info, void *userData), void *userData) { if (call == NULL) { return 0; } #ifdef HFLASH_USE_FLASH_MEM HFlashPageInfo page; uint8_t result = 0; for (uint32_t i = 0; i < sPageInfo.useNum; ++i) { if (HFlashMemRead(AdjustPageAddrOffset(sInfo.pageAddr, i), &page, sizeof(HFlashPageInfo)) == 0) { LogE("read page table[0x%08x] faild", AdjustPageAddrOffset(sInfo.pageAddr, i)); return 0; } result = call(i, &page, userData); if (result) { break; } } return result; #else const uint32_t pageNum = FAST_MIN(uint32_t, sPageInfo.useNum, (HFLASH_BLOCK_SIZE / sizeof(HFlashPageInfo))); HFlashPageInfo *buff = (HFlashPageInfo *)HFLASH_MALLOC(pageNum * sizeof(HFlashPageInfo)); if (buff == NULL) { LogE("malloc faild"); return 0; } uint8_t result = 0; for (uint32_t i = 0; i < sPageInfo.useNum; i += pageNum) { const uint32_t num = FAST_MIN(uint32_t, sPageInfo.useNum - i, pageNum); if (ReadFlashCall(AdjustPageAddrOffset(sInfo.pageAddr, i), buff, AdjustPageByte(num)) == 0) { LogE("read page table[0x%08x] faild", AdjustPageAddrOffset(sInfo.pageAddr, i)); break; } for (uint32_t j = 0; j < num; ++j) { result = call(i + j, buff + j, userData); if (result) { break; } } if (result) { break; } } HFLASH_FREE(buff); return result; #endif } ///< 检查是否重叠, 重叠返回1 static uint8_t _CreatePageInfoHelper(uint32_t index, HFlashPageInfo *info, void *userData) { if (info->invalid) { return 0; } HFlashPageInfo *cache = (HFlashPageInfo *)userData; return IsOverLap(info->addr, info->size, cache->addr, cache->size); } static uint8_t ScanAvailablePage(uint32_t index, HFlashPageInfo *info, void *userData) { uint32_t *result = (uint32_t *)userData; if (info->invalid == 0) { return 0; } *result = index; return 1; } static uint8_t CreatePageInfo(HFlashAddr_t addr, uint32_t size) { HFlashPageInfo info; memset(&info, 0, sizeof(HFlashPageInfo)); info.addr = addr; info.size = size; // 检查页表地址是否和当前页表地址范围内存在重叠 if (ScanPage(_CreatePageInfoHelper, &info)) { FATAL_ERROR("addr[0x%08x] size[%d] exist range Error", addr, size); return 0; } uint32_t index = 0; if (ScanPage(ScanAvailablePage, &index)) { // 如果找到空闲页, 覆盖之前的页 info.crc32 = GetFlashCrc32(info.addr, info.useSize); WritePage(index, &info); return 1; } if (sPageInfo.useNum >= sPageInfo.pageNum) { FATAL_ERROR("page table is full"); return 0; } // 写入新页表 index = sPageInfo.useNum++; info.crc32 = GetFlashCrc32(info.addr, info.useSize); WritePage(index, &info); return 1; } static uint8_t _FindCacheHelper(uint32_t index, HFlashPageInfo *info, void *userData) { if (info->invalid) { return 0; } HFlashCacheInfo *cache = (HFlashCacheInfo *)userData; if (info->addr != cache->info.addr) { return 0; } memset(cache, 0, sizeof(HFlashCacheInfo)); memcpy(cache->info.reverse, info->reverse, sizeof(HFlashPageInfo)); cache->pos = index; return 1; } ///< 查找缓存, 不存在就去查表, 表也不存在就去创建 static HFlashCacheInfo *FindCache(HFlashAddr_t addr) { uint8_t currMin = 0xFF; uint8_t fastCoolDown = 0; HFlashCacheInfo cache; for (uint16_t i = 0; i < sInfo.pageCacheUseNum; ++i) { currMin = FAST_MIN(uint8_t, currMin, sInfo.pageCache[i].heat); fastCoolDown = fastCoolDown || sInfo.pageCache[i].heat >= MAX_HEAT; if (sInfo.pageCache[i].info.addr != addr) { continue; } sInfo.pageCache[i].heat = FAST_MIN(uint8_t, sInfo.pageCache[i].heat + 1, MAX_HEAT); if (i == 0) { return &sInfo.pageCache[i]; } // 这里需要根据热度交换缓存位置 if (sInfo.pageCache[i].heat > sInfo.pageCache[i - 1].heat) { cache = sInfo.pageCache[i]; sInfo.pageCache[i] = sInfo.pageCache[i - 1]; sInfo.pageCache[i - 1] = cache; --i; } return &sInfo.pageCache[i]; } // 没有找到, 先降低温度 if (sInfo.pageCacheUseNum && (currMin > 0 || fastCoolDown)) { // 达到最大热度, 需要快速降温 const uint16_t mask = -((uint16_t)fastCoolDown); for (uint16_t i = 0; i < sInfo.pageCacheUseNum; ++i) { sInfo.pageCache[i].heat = ((sInfo.pageCache[i].heat >> 1) & mask) | ((sInfo.pageCache[i].heat - currMin) & ~mask); } } // 查找到了就直接替换最后面的就行 memset(&cache, 0, sizeof(HFlashCacheInfo)); cache.info.addr = addr; if (ScanPage(_FindCacheHelper, &cache)) { const uint16_t index = FAST_MIN(uint16_t, sInfo.pageCacheUseNum, sInfo.pageCacheSize - 1); if (sInfo.pageCacheUseNum < sInfo.pageCacheSize) { ++sInfo.pageCacheUseNum; } // 更新Crc32 if (sInfo.pageCache[index].waitCrc) { sInfo.pageCache[index].info.crc32 = GetFlashCrc32(sInfo.pageCache[index].info.addr, sInfo.pageCache[index].info.useSize); sInfo.pageCache[index].waitWrite = 1; } // 如果是延迟写入的, 需要先写入再替换 if (sInfo.pageCache[index].waitWrite) { WritePage(sInfo.pageCache[index].pos, &sInfo.pageCache[index].info); sInfo.pageCache[index].waitWrite = 0; } memcpy(&sInfo.pageCache[index], &cache, sizeof(HFlashCacheInfo)); return &sInfo.pageCache[index]; } LogE("addr[0x%08x] not find", addr); return NULL; } void HFlashInitCallback(HFlashReadCallback read, HFlashWriteCallback write, HFlashEraseCallback erase) { #ifndef HFLASH_USE_FLASH_MEM sInfo.read = read; sInfo.write = write; sInfo.erase = erase; #endif } uint16_t HFlashGetVersion(HFlashAddr_t addr, HFlashVersionInfo *info) { uint16_t pageVersion = 0; if (info == NULL) { return pageVersion; } ReadFlashCall(addr, info, sizeof(HFlashVersionInfo)); HFlashCacheInfo *page = FindCache(addr); if (page == NULL) { return pageVersion; } pageVersion = page->info.version; if (page->info.size >= sizeof(HFlashVersionInfo)) { HFlashRead(addr, info, sizeof(HFlashVersionInfo)); } return pageVersion; } void HFlashSetPageCache(HFlashCacheInfo *pageInfo, uint16_t size) { sInfo.pageCache = pageInfo; sInfo.pageCacheUseNum = 0; sInfo.pageCacheSize = size; } void HFlashInitProtectCache(HFlashProtectInfo *protectInfo, void *bitMap, uint32_t size) { memset(protectInfo, 0, sizeof(HFlashProtectInfo)); #if HFLASH_USE_BITMAP if (HBitMapInit(bitMap, HFLASH_CALC_BITMAP_SIZE(size)) == 0) { FATAL_ERROR("bitmap init fail"); return ; } protectInfo->bitMap = bitMap; #endif } void HFlashSetProtectCache(HFlashProtectInfo *protectInfo, uint16_t size) { ResetRuntimeState(); sInfo.protectInfo = protectInfo; sInfo.protectCacheSize = size; sInfo.protectUseNum = 0; #if HFLASH_USE_BITMAP for (uint16_t i = 0; i < size; ++i) { if (sInfo.protectInfo[i].bitMap != NULL) { continue; } FATAL_ERROR("protect cache[0x%08x] not init", sInfo.protectInfo[i].addr); return ; } #endif } void HFlashSetPageAddr(HFlashAddr_t addr, uint32_t size) { if (IS_NOT_4K(addr) || IS_NOT_4K(size)) { FATAL_ERROR("not align page size[0x%08x], size[%x]", addr, size); return ; } sInfo.pageAddr = addr; sInfo.pageSize = size; } void HFlashSetPageBackupAddr(HFlashAddr_t addr, uint32_t size) { if (IS_NOT_4K(addr) || IS_NOT_4K(size) || size != sInfo.pageSize) { FATAL_ERROR("not align page size[0x%08x], size[%x]", addr, size); return ; } if (IsOverLap(sInfo.pageAddr, sInfo.pageSize, addr, size)) { FATAL_ERROR("page backup overlap src/dst[0x%08x][0x%08x]", sInfo.pageAddr, addr); return ; } for (uint16_t i = 0; i < sInfo.protectUseNum; ++i) { HFlashProtectInfo *info = &sInfo.protectInfo[i]; if (IsOverLap(addr, size, info->backupAddr, AdjustProtectBackupSize(info->addr, info->size))) { FATAL_ERROR("page backup overlap protect backup[0x%08x][0x%08x]", addr, info->backupAddr); return ; } } sInfo.pageBackupAddr = addr; } static uint8_t CheckProtectConflict(HFlashAddr_t addr, uint32_t size, HFlashAddr_t backupAddr) { HFlashAddr_t adjustAddr = 0; uint32_t backupSize = 0; if (GetProtectBackupRange(addr, size, &adjustAddr, &backupSize) == 0) { return 0; } if (IsOverLap(adjustAddr, backupSize, sInfo.pageAddr, sInfo.pageSize)) { FATAL_ERROR("protect area overlap page[0x%08x][0x%08x]", addr, sInfo.pageAddr); return 0; } if (sInfo.pageBackupAddr && IsOverLap(backupAddr, backupSize, sInfo.pageBackupAddr, sInfo.pageSize)) { FATAL_ERROR("protect backup overlap page backup[0x%08x][0x%08x]", backupAddr, sInfo.pageBackupAddr); return 0; } if (IsOverLap(adjustAddr, backupSize, backupAddr, backupSize)) { FATAL_ERROR("protect backup overlap src/dst[0x%08x][0x%08x]", addr, backupAddr); return 0; } for (uint16_t i = 0; i < sInfo.protectUseNum; ++i) { HFlashProtectInfo *info = &sInfo.protectInfo[i]; HFlashAddr_t infoAdjustAddr = 0; uint32_t infoBackupSize = 0; if (GetProtectBackupRange(info->addr, info->size, &infoAdjustAddr, &infoBackupSize) == 0) { return 0; } if (info->addr == addr) { FATAL_ERROR("protect addr[0x%08x] duplicate", addr); return 0; } if (IsOverLap(infoAdjustAddr, infoBackupSize, adjustAddr, backupSize)) { FATAL_ERROR("protect area overlap[0x%08x][0x%08x]", info->addr, addr); return 0; } if (info->backupAddr == backupAddr) { FATAL_ERROR("protect backup addr[0x%08x] duplicate", backupAddr); return 0; } if (IsOverLap(info->backupAddr, infoBackupSize, backupAddr, backupSize)) { FATAL_ERROR("protect backup overlap[0x%08x][0x%08x]", info->backupAddr, backupAddr); return 0; } } return 1; } void HFlashClearProtectAddr() { ResetRuntimeState(); sInfo.protectUseNum = 0; if (sInfo.protectInfo != NULL && sInfo.protectCacheSize) { for (uint16_t i = 0; i < sInfo.protectCacheSize; ++i) { ClearProtectInfoEntry(&sInfo.protectInfo[i]); } } } void HFlashAddProtectAddr(HFlashAddr_t addr, uint32_t size, HFlashAddr_t backupAddr) { if (size == 0) { FATAL_ERROR("protect size is 0 addr[0x%08x]", addr); return ; } if (IS_NOT_4K(backupAddr)) { FATAL_ERROR("not align backup addr[0x%08x]", backupAddr); return ; } if (sInfo.protectInfo == NULL || sInfo.protectCacheSize == 0) { FATAL_ERROR("protectCache is null"); return ; } if (sInfo.protectUseNum >= sInfo.protectCacheSize) { FATAL_ERROR("protect is full"); return ; } if (CheckProtectConflict(addr, size, backupAddr) == 0) { LogE("protect addr[0x%08x] conflict", addr); return ; } HFlashProtectInfo *info = &sInfo.protectInfo[sInfo.protectUseNum]; ClearProtectInfoEntry(info); #if HFLASH_USE_BITMAP if (HBitMapGetBitLen(info->bitMap) < (AdjustProtectBackupSize(addr, size) >> 12)) { FATAL_ERROR("protect addr[0x%08x] bitmap too small", addr); return ; } #endif info->addr = addr; info->size = size; info->backupAddr = backupAddr; ++sInfo.protectUseNum; } void HFlashDelProtectAddr(HFlashAddr_t addr) { const int16_t index = FindProtectAddrIndex(addr); if (index < 0) { FATAL_ERROR("protect addr[0x%08x] not exist", addr); return ; } ResetRuntimeState(); for (uint16_t i = (uint16_t)index; i + 1 < sInfo.protectUseNum; ++i) { #if HFLASH_USE_BITMAP HBitMapType *currBitMap = sInfo.protectInfo[i].bitMap; sInfo.protectInfo[i] = sInfo.protectInfo[i + 1]; sInfo.protectInfo[i].bitMap = currBitMap; HBitMapFill(sInfo.protectInfo[i].bitMap, 0); #else sInfo.protectInfo[i] = sInfo.protectInfo[i + 1]; #endif } --sInfo.protectUseNum; ClearProtectInfoEntry(&sInfo.protectInfo[sInfo.protectUseNum]); } static uint8_t CheckBackupArea() { if (sInfo.pageBackupAddr == 0) { FATAL_ERROR("page backup addr is null"); return 0; } if (IsOverLap(sInfo.pageAddr, sInfo.pageSize, sInfo.pageBackupAddr, sInfo.pageSize)) { FATAL_ERROR("page backup overlap src/dst[0x%08x][0x%08x]", sInfo.pageAddr, sInfo.pageBackupAddr); return 0; } for (uint16_t i = 0; i < sInfo.protectUseNum; ++i) { HFlashProtectInfo *info = &sInfo.protectInfo[i]; HFlashAddr_t adjustAddr = 0; uint32_t backupSize = 0; if (GetProtectBackupRange(info->addr, info->size, &adjustAddr, &backupSize) == 0) { return 0; } if (IsOverLap(adjustAddr, backupSize, info->backupAddr, backupSize)) { FATAL_ERROR("protect backup overlap src/dst[0x%08x][0x%08x]", info->addr, info->backupAddr); return 0; } if (IsOverLap(info->backupAddr, backupSize, sInfo.pageBackupAddr, sInfo.pageSize)) { FATAL_ERROR("protect backup overlap page backup[0x%08x][0x%08x]", info->backupAddr, sInfo.pageBackupAddr); return 0; } } for (uint16_t i = 0; i < sInfo.protectUseNum; ++i) { for (uint16_t j = i + 1; j < sInfo.protectUseNum; ++j) { HFlashAddr_t adjustAddrI = 0; HFlashAddr_t adjustAddrJ = 0; uint32_t backupSizeI = 0; uint32_t backupSizeJ = 0; if (GetProtectBackupRange(sInfo.protectInfo[i].addr, sInfo.protectInfo[i].size, &adjustAddrI, &backupSizeI) == 0 || GetProtectBackupRange(sInfo.protectInfo[j].addr, sInfo.protectInfo[j].size, &adjustAddrJ, &backupSizeJ) == 0) { return 0; } if (IsOverLap(adjustAddrI, backupSizeI, adjustAddrJ, backupSizeJ)) { FATAL_ERROR("protect area overlap[0x%08x][0x%08x]", sInfo.protectInfo[i].addr, sInfo.protectInfo[j].addr); return 0; } if (IsOverLap(sInfo.protectInfo[i].backupAddr, backupSizeI, sInfo.protectInfo[j].backupAddr, backupSizeJ)) { FATAL_ERROR("protect backup overlap[0x%08x][0x%08x]", sInfo.protectInfo[i].backupAddr, sInfo.protectInfo[j].backupAddr); return 0; } } } return 1; } static uint8_t _Print(uint32_t index, HFlashPageInfo *info, void *userData) { uint32_t *arg1 = (uint32_t *)userData; if (*arg1 == -1) { HSHELL_PRINTFL("page[%d], invalid[%d], addr[0x%08x][%u], useSize[0x%x][%d], size[0x%x][%d], modifyCount[%d], crc32[0x%x], version[%d]", index, info->invalid, info->addr, info->addr, info->useSize, info->useSize, info->size, info->size, info->modifyCount, info->crc32, info->version); return 0; } if (index == *arg1) { HSHELL_PRINTFL("page[%d], invalid[%d], addr[0x%08x][%u], useSize[0x%x][%d], size[0x%x][%d], modifyCount[%d], crc32[0x%x], version[%d]", index, info->invalid, info->addr, info->addr, info->useSize, info->useSize, info->size, info->size, info->modifyCount, info->crc32, info->version); return 1; } return 0; } #if HFLASH_USE_HSHELL static void Shell(HSHELL_FUNC_ARGS) { uint32_t arg1 = 0; if (HSHellToUint32(tokens, tokensLen, 1, &arg1) == 0) { arg1 = -1; } switch (key) { case kShellPageInfo: { ScanPage(_Print, &arg1); for (uint16_t i = 0; i < sInfo.pageCacheUseNum; ++i) { HSHELL_PRINTFL("Cache index[%d], addr[0x%08x], useSize[0x%x][%d], size[0x%x][%d], modifyCount[%d], crc32[0x%x], version[%d], heat[%d]", i, sInfo.pageCache[i].info.addr, sInfo.pageCache[i].info.useSize, sInfo.pageCache[i].info.useSize, sInfo.pageCache[i].info.size, sInfo.pageCache[i].info.size, sInfo.pageCache[i].info.modifyCount, sInfo.pageCache[i].info.crc32, sInfo.pageCache[i].info.version, sInfo.pageCache[i].heat); } } break; case kShellDelUseDataPage: { HFlashCacheInfo *cache = FindCache(arg1); if (cache == NULL) { HSHELL_PRINTFL("addr[0x%08x] not register", arg1); return ; } cache->info.useSize = 0; WriteCachePage(cache); } break; case kShellDelPage: { HFlashCacheInfo *cache = FindCache(arg1); if (cache == NULL) { HSHELL_PRINTFL("addr[0x%08x] not register", arg1); return ; } cache->info.invalid = 1; WriteCachePage(cache); } break; case kShellResetPage: { HFlashResetPage(); } break; case kShellRestorePage: { RestoreBackupRange(sInfo.pageAddr, AdjustPageByte(sPageInfo.pageNum + 1)); } break; #ifdef HFLASH_USE_FLASH_MEM case kShellFlashMemInfo: { const HFlashMemOpts *opt = HFlashMemGetOpt(); if (opt == NULL) { break; } for (uint8_t i = 0; i < opt->cacheSize; ++i) { HSHELL_PRINTFL("addr[0x%08x], offset[%d], eraseStatus[%d], isDirty[%d], heat[%d]", opt->cache[i].addr, opt->cache[i].offset, opt->cache[i].eraseStatus, opt->cache[i].isDirty, opt->cache[i].heat); } } break; #endif default: break; } } #endif void HFlashInitCheck() { #if HFLASH_USE_HSHELL HSHellRegister(sShellMatch, sizeof(sShellMatch) / sizeof(HShellMatch), Shell, 0); #endif if (sInfo.pageCache == NULL || sInfo.pageCacheSize == 0) { FATAL_ERROR("pageCache is null"); return ; } if (CheckBackupArea() == 0) { LogE("Backup area check faild"); return ; } const uint32_t num = sInfo.pageSize / sizeof(HFlashPageInfo); do { if (ReadFlashCall(sInfo.pageAddr, sPageInfo.reverse, sizeof(sPageInfo)) == 0) { LogE("Read page table[0x%08x] faild", sInfo.pageAddr); break; } LogD("num[%d], useNum[%d], pageNum[%d]", num, sPageInfo.useNum, sPageInfo.pageNum); // 检查是不是无效页表, 如果是就去检查备份, 如果备份也是无效的, 说明是首次初始化 uint8_t invalid = sPageInfo.pageNum > num; invalid = invalid || sPageInfo.useNum > num; invalid = invalid || sPageInfo.useNum > sPageInfo.pageNum; invalid = invalid || GetFlashCrc32(AdjustPageAddr(sInfo.pageAddr), AdjustPageByte(sPageInfo.useNum)) != sPageInfo.crc32; if (invalid == 0) { // 检查通过 return ; } LogD("page table is invalid, check backup table"); // 备份校验 if (ReadBackup(sInfo.pageAddr, sPageInfo.reverse, sizeof(sPageInfo)) == 0) { LogE("Read backup page table[0x%08x] faild", sInfo.pageAddr); break; } invalid = sPageInfo.pageNum > num; invalid = invalid || sPageInfo.useNum > num; invalid = invalid || sPageInfo.useNum > sPageInfo.pageNum; invalid = invalid || GetBackupCrc32(AdjustPageAddr(sInfo.pageAddr), AdjustPageByte(sPageInfo.useNum)) != sPageInfo.crc32; if (invalid) { // 备份也无效, 首次创建, 去初始化数据 LogD("backup page table is invalid, init data"); break; } // 备份校验通过, 恢复全备份数据 RestoreBackupRange(sInfo.pageAddr, sInfo.pageSize); return ; } while (0); memset(sPageInfo.reverse, 0, sizeof(sPageInfo)); sPageInfo.pageNum = num; } ///< 检查是否重叠, 重叠返回1 static uint8_t _CheckOverLap(uint32_t index, HFlashPageInfo *info, void *userData) { if (info->invalid) { return 0; } HFlashCacheInfo *cache = (HFlashCacheInfo *)userData; if (cache->pos == index) { return 0; } return IsOverLap(info->addr, info->size, cache->info.addr, cache->info.size); } static uint8_t HasProtectOverlap(HFlashAddr_t addr, uint32_t size) { for (uint16_t i = 0; i < sInfo.protectUseNum; ++i) { if (IsOverLap(addr, size, sInfo.protectInfo[i].addr, sInfo.protectInfo[i].size)) { return 1; } } return 0; } void HFlashRegister(HFlashAddr_t addr, uint32_t size) { if (IS_NOT_4(size)) { FATAL_ERROR("size[%d] not align 4", size); return ; } if (HasProtectOverlap(addr, size) && IsProtect(addr, size) == 0) { FATAL_ERROR("addr[0x%08x] size[%d] partial overlap protect range", addr, size); return ; } HFlashCacheInfo *cache = FindCache(addr); if (cache == NULL) { // 首次创建页表, 不需要检查 LogD("create addr[0x%08x] size[%d]", addr, size); if (CreatePageInfo(addr, size) == 0) { LogE("Create addr[0x%08x] size[%d] faild", addr, size); } StartSyncBackupTimer(); return ; } // 检查是否需要更新页表存储的大小 if (size != cache->info.size) { LogD("Update addr[0x%08x] size[%d], useSize[%d], oldSize[%d]", addr, size, cache->info.useSize, cache->info.size); cache->info.size = size; // 检查页表地址是否和当前页表地址范围内存在重叠 if (ScanPage(_CheckOverLap, &cache->info)) { FATAL_ERROR("addr[0x%08x] size[%d] exist range Error", addr, size); return ; } cache->waitWrite = 1; } // 已使用空间大于容量, 页表数据异常或者容量被缩小, 丢弃数据, 如果是保护区域下面会恢复 if (cache->info.useSize > size) { LogE("addr[0x%08x] useSize[%d] > size[%d]", addr, cache->info.useSize, size); cache->info.useSize = 0; cache->waitWrite = 1; } // 检查是否在保护区域, 不是保护区域不需要检查crc校验 if (IsProtect(addr, size) == 0) { return ; } // 检查保护区域的crc是否相同 if (GetFlashCrc32(addr, cache->info.useSize) == cache->info.crc32) { return ; } // 先恢复内容区域 LogD("addr[0x%08x] size[%d] crc32 not match, start restore", addr, size); RestoreBackupRange(cache->info.addr, cache->info.size); // 如果恢复后还校验失败, 那就恢复对应页表 const uint32_t contentCrc = GetFlashCrc32(cache->info.addr, cache->info.useSize); if (contentCrc == cache->info.crc32) { return ; } // 恢复页表后重新读取 LogE("addr[0x%08x] size[%d] crc32 not match, restore faild", cache->info.addr, cache->info.size); RestorePage(cache->pos); ReadPage(cache->pos, &cache->info); do { // 如果恢复页表数据后, 大小不一致, 说明用户在调整大小, 放弃数据, 不恢复 if (cache->info.size != size) { break; } // 恢复后数据校验不一致, 需要重置 if (contentCrc != cache->info.crc32) { break; } return ; } while (0); // 恢复后数据还是错误的, 需要将该页表数据重新初始化 LogE("addr[0x%08x] size[%d] newSize[%d] crc32 not match", cache->info.addr, cache->info.size, size); memset(cache->info.reverse, 0, sizeof(cache->info)); cache->info.addr = addr; cache->info.useSize = 0; cache->info.size = size; cache->info.crc32 = GetFlashCrc32(cache->info.addr, cache->info.useSize); WriteCachePage(cache); } uint8_t HFlashWrite(HFlashAddr_t addr, const void *data, uint32_t size) { // 检查是否存在致命性错误, 使用的地址不在注册页表中 uint8_t result = 0; HFlashCacheInfo *cache = FindCache(addr); if (cache == NULL) { FATAL_ERROR("addr[0x%08x] not register", addr); return result; } // 检查写入数据大小是否超出注册提供的大小范围 if (cache->info.size < size) { FATAL_ERROR("addr[0x%08x], size[%d], max size[%d] overflow", addr, size, cache->info.size); return result; } // 更新使用长度, 直接重写比较短的数据不要影响使用长度 if (cache->info.useSize < size) { cache->info.useSize = size; } result = WriteFlash(addr, data, size); if (result) { cache->info.crc32 = GetFlashCrc32(addr, cache->info.useSize); } WriteCachePage(cache); // 检查是否在保护区域, 需要的话需要写入等待备份 if (IsProtect(addr, size)) { AddBackupAddr(addr, size); } return result; } static uint8_t WriteOffset(HFlashAddr_t addr, uint32_t offset, const void *data, uint32_t size, uint8_t needSetZero) { uint8_t result = 0; HFlashCacheInfo *cache = FindCache(addr); if (cache == NULL) { FATAL_ERROR("addr[0x%08x] not register", addr); return result; } const uint32_t useSize = offset + size; // 检查写入数据大小是否超出注册提供的大小范围 if (cache->info.size < useSize) { FATAL_ERROR("addr[0x%08x] size[%d] overflow", addr, useSize); return result; } // 更新使用长度, 将跨越的部分填充0 if (cache->info.useSize < useSize) { if (needSetZero && cache->info.useSize < offset) { WriteFlashValue(addr + cache->info.useSize, offset - cache->info.useSize, 0); } cache->info.useSize = useSize; } result = WriteFlash(addr + offset, data, size); cache->waitCrc = 1; WriteCachePage(cache); // 检查是否在保护区域, 需要的话需要写入等待备份 if (IsProtect(addr, size)) { // 仅备份修改的部分 AddBackupOffsetAddr(addr, offset, size); } return result; } uint8_t HFlashWriteOffset(HFlashAddr_t addr, uint32_t offset, const void *data, uint32_t size) { return WriteOffset(addr, offset, data, size, 1); } uint8_t HFlashWriteOffsetValue(HFlashAddr_t addr, uint32_t offset, uint8_t value, uint32_t size) { uint8_t result = 0; HFlashCacheInfo *cache = FindCache(addr); if (cache == NULL) { FATAL_ERROR("addr[0x%08x] not register", addr); return result; } const uint32_t useSize = offset + size; if (cache->info.size < useSize) { FATAL_ERROR("addr[0x%08x] size[%d] overflow", addr, useSize); return result; } if (cache->info.useSize < useSize) { if (cache->info.useSize < offset) { WriteFlashValue(addr + cache->info.useSize, offset - cache->info.useSize, 0); } cache->info.useSize = useSize; } result = WriteFlashValue(addr + offset, size, value); cache->waitCrc = 1; WriteCachePage(cache); if (IsProtect(addr, size)) { AddBackupOffsetAddr(addr, offset, size); } return result; } uint8_t HFlashWriteRawOffset(HFlashAddr_t addr, uint32_t offset, const void *data, uint32_t size) { return WriteOffset(addr, offset, data, size, 0); } void HFlashStreamBegin(HFlashAddr_t addr) { HFlashCacheInfo *cache = FindCache(addr); if (cache == NULL) { FATAL_ERROR("addr[0x%08x] not register", addr); return ; } cache->waitWrite = 1; cache->waitCrc = 1; cache->info.crc32 = 0xFFFFFFFF; cache->info.useSize = 0; } uint8_t HFlashStreamWrite(HFlashAddr_t addr, const void *data, uint32_t size) { uint8_t result = 0; HFlashCacheInfo *cache = FindCache(addr); if (cache == NULL) { FATAL_ERROR("addr[0x%08x] not register", addr); return result; } if (cache->info.useSize + size > cache->info.size) { LogE("addr[0x%08x] size[%d][%d] overflow", addr, cache->info.useSize + size, cache->info.size); return result; } result = WriteFlash(addr + cache->info.useSize, data, size); cache->waitWrite = 1; cache->waitCrc = 1; cache->info.useSize += size; ++cache->info.modifyCount; return result; } void HFlashStreamEnd(HFlashAddr_t addr) { HFlashCacheInfo *cache = FindCache(addr); if (cache == NULL) { FATAL_ERROR("addr[0x%08x] not register", addr); return ; } cache->info.crc32 = GetFlashCrc32(addr, cache->info.useSize); cache->waitCrc = 0; if (IsProtect(addr, cache->info.useSize)) { AddBackupAddr(addr, cache->info.useSize); } WriteCachePage(cache); } uint8_t HFlashRawWrite(HFlashAddr_t addr, const void *data, uint32_t size) { return WriteFlash(addr, data, size); } uint8_t HFlashRead(HFlashAddr_t addr, void *data, uint32_t size) { HFlashCacheInfo *cache = FindCache(addr); if (cache == NULL) { FATAL_ERROR("addr[0x%08x] not register", addr); memset(data, 0, size); return 0; } // 超出部分填充0 if (cache->info.useSize < size) { memset((uint8_t *)data + cache->info.useSize, 0, size - cache->info.useSize); } const uint32_t readSize = FAST_MIN(uint32_t, size, cache->info.useSize); return ReadFlashCall(addr, data, readSize); } uint8_t HFlashReadOffset(HFlashAddr_t addr, uint32_t offset, void *data, uint32_t size) { HFlashCacheInfo *cache = FindCache(addr); if (cache == NULL) { FATAL_ERROR("addr[0x%08x] not register", addr); memset(data, 0, size); return 0; } // 读取的偏移量超出使用长度 if (cache->info.useSize < offset) { memset(data, 0, size); return 0; } // 读取的数据超出使用长度, 将使用长度后面填充0 const uint32_t useSize = offset + size; if (useSize > cache->info.useSize) { const uint32_t remain = useSize - cache->info.useSize; memset((uint8_t *)data + size - remain, 0, remain); size -= remain; } return ReadFlashCall(addr + offset, data, size); } uint8_t HFlashRawRead(HFlashAddr_t addr, void *data, uint32_t size) { return ReadFlashCall(addr, data, size); } static void UpdateVersionInner(HFlashAddr_t addr, uint16_t newVersion, HFlashUpdateVersionCallback callback, void *userData, uint8_t onlyUpgrade) { HFlashCacheInfo *cache = FindCache(addr); if (cache == NULL) { FATAL_ERROR("addr[0x%08x] not register", addr); return ; } if (cache->info.version == newVersion) { return ; } if (onlyUpgrade && (newVersion < cache->info.version)) { return ; } const uint16_t oldVersion = cache->info.version; cache->info.version = newVersion; if (callback) { callback(addr, oldVersion, newVersion, userData); } WriteCachePage(cache); } void HFlashUpdateVersion(HFlashAddr_t addr, uint16_t newVersion, HFlashUpdateVersionCallback callback, void *userData) { UpdateVersionInner(addr, newVersion, callback, userData, 0); } void HFlashUpgradeVersion(HFlashAddr_t addr, uint16_t newVersion, HFlashUpdateVersionCallback callback, void *userData) { UpdateVersionInner(addr, newVersion, callback, userData, 1); } void HFlashDefaultUpdateVersion(HFlashAddr_t addr, uint16_t oldVersion, uint16_t newVersion, void *userData) { (void)(oldVersion); (void)(newVersion); (void)(userData); HFlashDeleteData(addr); } void HFlashDeleteData(HFlashAddr_t addr) { HFlashSetUseSize(addr, 0, 0); } uint32_t HFlashGetUseSize(HFlashAddr_t addr) { HFlashCacheInfo *cache = FindCache(addr); if (cache == NULL) { FATAL_ERROR("addr[0x%08x] not register", addr); return 0; } return cache->info.useSize; } uint8_t HFlashSetUseSize(HFlashAddr_t addr, uint32_t size, uint8_t delayCrc32) { HFlashCacheInfo *cache = FindCache(addr); if (cache == NULL) { LogE("addr[0x%08x] not register", addr); return 0; } if (size > cache->info.size) { LogE("addr[0x%08x] useSize[%d] overflow size[%d]", addr, size, cache->info.size); return 0; } cache->info.useSize = size; cache->waitCrc = !!delayCrc32; WriteCachePage(cache); if (size) { AddBackupAddr(addr, size); } return 1; } uint32_t HFlashGetSize(HFlashAddr_t addr) { HFlashCacheInfo *cache = FindCache(addr); if (cache == NULL) { FATAL_ERROR("addr[0x%08x] not register", addr); return 0; } return cache->info.size; } uint32_t HFlashGetCrc32(HFlashAddr_t addr) { HFlashCacheInfo *cache = FindCache(addr); if (cache == NULL) { FATAL_ERROR("addr[0x%08x] not register", addr); return 0xFFFFFFFF; } return cache->info.crc32; } uint32_t HFlashCalcCrc32(HFlashAddr_t addr) { HFlashCacheInfo *cache = FindCache(addr); if (cache == NULL) { FATAL_ERROR("addr[0x%08x] not register", addr); return 0xFFFFFFFF; } return GetFlashCrc32(addr, cache->info.useSize); } void HFlashSync() { SyncCachePage(); SyncPageInfo(); SyncBackup(); #ifdef HFLASH_USE_FLASH_MEM HFlashMemSync(); #endif } void HFlashFreeCache() { HFlashSync(); sInfo.pageCacheUseNum = 0; #ifdef HFLASH_USE_FLASH_MEM HFlashMemFreeCache(); #endif } void HFlashResetPage() { sPageInfo.useNum = 0; SyncPageInfo(); }