HCoreBase/src/HFlashServer.c
2026-04-30 10:54:37 +08:00

2122 lines
62 KiB
C

#include "HFlashServer.h"
#include "HDLog.h"
#include "HTimer.h"
#if HFLASH_USE_HSHELL
#include "HShellLex.h"
#endif
#include <stdio.h>
#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 <nmmintrin.h>
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();
}