2122 lines
62 KiB
C
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();
|
|
}
|