diff --git a/include/HFlashServer.h b/include/HFlashServer.h new file mode 100644 index 0000000..2cd1510 --- /dev/null +++ b/include/HFlashServer.h @@ -0,0 +1,141 @@ +/** + * 日期: 2025-11-27 + * 作者: coffee + * 描述: Flash通用服务模块, 用于保证性Flash操作 + */ + + +#ifndef __H_FLASH_SERVER_H__ +#define __H_FLASH_SERVER_H__ + + +///< Flash块大小, 按块操作, 2的幂关系 +#ifndef HFLASH_BLOCK_SIZE +#define HFLASH_BLOCK_SIZE (4096) +#endif + +///< 获取缓存内存, 需要大于Flash一块大小 +#ifndef HFLASH_MALLOC +#define HFLASH_MALLOC(size) malloc(size) +#endif + +///< 释放缓存 +#ifndef HFLASH_FREE +#define HFLASH_FREE(ptr) free(ptr) +#endif + +#include +#include + +///< Flash地址类型 +typedef uint32_t HFlashAddr_t; + +///< Flash页表信息 +typedef union HFlashPageInfo { + uint8_t reverse[32]; ///< 每页的信息占用32字节 + struct __attribute__((packed)) { + HFlashAddr_t addr; ///< 地址 + uint32_t crc32; ///< 使用大小内容的CRC32 + uint32_t size : 24; ///< 大小 + uint32_t useSize : 24; ///< 使用大小 + uint16_t version; ///< 当前页数据的版本 + uint32_t modifyCount; ///< 修改次数 + }; +} HFlashPageInfo; + +typedef struct HFlashCacheInfo { + HFlashPageInfo info; ///< 页表信息 + uint32_t pos : 19; ///< 存储页表信息的位置 + uint32_t heat : 4; ///< 热度优先级 +} HFlashCacheInfo; + + +/** + * @brief HFlashEraseCallback 擦除回调 + * @param addr Flash地址 + * @return 1: 擦除成功 0: 擦除失败 + */ +typedef uint8_t (*HFlashEraseCallback)(HFlashAddr_t addr); + +/** + * @brief HFlashReadCallback 读取回调 + * @param addr Flash地址 + * @param data Flash读取写入的缓存数据内存 + * @param size 缓存大小 + * @return 1: 读取成功 0: 读取失败 + */ +typedef uint8_t (*HFlashReadCallback)(HFlashAddr_t addr, uint8_t *data, uint32_t size); + +/** + * @brief HFlashWriteCallback 写入回调 + * @param addr Flash地址 + * @param data Flash读取写入的缓存数据内存 + * @param size 缓存大小 + * @return 1: 写入成功 0: 写入失败 + */ +typedef uint8_t (*HFlashWriteCallback)(HFlashAddr_t addr, uint8_t *data, uint32_t size); + +/** + * @brief HFlashInitCallback 设置Flash初始化回调 + * @param read 读取回调 + * @param write 写入回调 + * @param erase 擦除回调 + */ +void HFlashInitCallback(HFlashReadCallback read, HFlashWriteCallback write, HFlashEraseCallback erase); + +/** + * @brief HFlashSetPageCache 设置页表缓存, 内部不构建内存, 由外部分配 + * @param pageInfo 页表信息缓存 + * @param size 大小 + */ +void HFlashSetPageCache(HFlashCacheInfo *pageInfo, uint16_t size); + +/** + * @brief HFlashSetPageAddr 设置页表地址 + * @param addr 地址 + * @param size 大小 + */ +void HFlashSetPageAddr(HFlashAddr_t addr, uint32_t size); + +/** + * @brief HFlashSetPageBackupAddr 设置页表备份地址 + * @param addr 地址 + * @param size 大小, 必须和页表地址大小相同 + */ +void HFlashSetPageBackupAddr(HFlashAddr_t addr, uint32_t size); + +/** + * @brief HFlashProtectAddr 设置保护地址, 内部会使用双备份区域 + * @param addr 地址 + * @param size 大小 + */ +void HFlashProtectAddr(HFlashAddr_t addr, uint32_t size); + +/** + * @brief HFlashProtectBackupAddr 设置保护备份地址 + * @param addr 地址 + * @param size 大小, 必须和保护地址大小相同 + */ +void HFlashProtectBackupAddr(HFlashAddr_t addr, uint32_t size); + +/** + * @brief HFlashInitCheck 在HFlashRegister前需要初始化检查, 用于检查页表是否可用, 不可用则需要初始化 + */ +void HFlashInitCheck(); + +/** + * @brief HFlashRegister 注册地址到页表 + * @param addr 地址 + * @param size 该地址占用的大小 + */ +void HFlashRegister(HFlashAddr_t addr, uint32_t size); + +/** + * @brief HFlashWrite 写入Flash, 需要注册的地址 + * @param addr 地址 + * @param data 写入数据 + * @param size 写入数据大小 + */ +void HFlashWrite(HFlashAddr_t addr, void *data, uint32_t size); + +#endif // __H_FLASH_SERVER_H__ diff --git a/src/HFlashServer.c b/src/HFlashServer.c new file mode 100644 index 0000000..865a011 --- /dev/null +++ b/src/HFlashServer.c @@ -0,0 +1,817 @@ + + +#include "HFlashServer.h" +#include "HDLog.h" +#include "HVector.h" + + +#if 1 +#include +static uint32_t sCrcValue; +void HSCrc32Reset() +{ + sCrcValue = 0xFFFFFFFF; +} +void HSCrc32Update(const uint8_t *data, size_t len) +{ + for (size_t i = 0; i < len; i++) { + sCrcValue = _mm_crc32_u8(sCrcValue, data[i]); + } +} + +uint32_t HSCrc32Get() +{ + return sCrcValue ^ 0xFFFFFFFF; +} +#endif + +#define FLASH_MIN(type, a, b) ((b) ^ (((a) ^ (b)) & (-(type)((a) < (b))))) + +// #define FATAL_ERROR(format, ...) LogE(format, ##__VA_ARGS__); while(1); +#define FATAL_ERROR(format, ...) LogE(format, ##__VA_ARGS__); + +#define IS_NOT_4(size) ((size & (4 - 1)) != 0) + +union PageInfo { + uint8_t reverse[32]; ///< 每页的信息占用32字节 + struct __attribute__((packed)) { + uint32_t crc32; ///< 页表内容的CRC32校验值 + uint32_t pageNum : 19; ///< 可用页数量 + uint32_t useNum : 19; ///< 已使用页数量 + uint32_t needBackupPage : 1; ///< 是否需要备份页表 + }; +}; + +struct Info { + HFlashReadCallback read; ///< 读取回调 + HFlashWriteCallback write; ///< 写入回调 + HFlashEraseCallback erase; ///< 擦除回调 + HFlashAddr_t pageAddr; ///< 页表地址 + HFlashAddr_t pageBackupAddr; ///< 页表备份地址 + uint32_t pageSize; ///< 页大小 + HFlashAddr_t protectAddr; ///< 保护区地址 + HFlashAddr_t protectBackupAddr; ///< 保护区备份地址 + uint32_t protectSize; ///< 保护区大小 + HFlashCacheInfo *pageCache; ///< 页表缓存 + uint16_t pageCacheSize; ///< 页表缓存大小 + uint16_t pageCacheUseNum; ///< 页表缓存使用页 +}; + +static struct Info sInfo; +static union PageInfo sPageInfo; + +// 需要备份的保护区地址页偏移 +static HVECTOR_DEFINE32(sNeedBackupOffset, 10); + + +static uint8_t RestoreBackup(HFlashAddr_t srcAddr, HFlashAddr_t dstAddr, uint32_t size); + +///< 检查地址是否在双备份保护区内 +static uint8_t IsProtect(HFlashAddr_t addr, uint32_t size) +{ + const HFlashAddr_t addrEnd = addr + size; + if (addrEnd < addr) { + FATAL_ERROR("addr[0x%08x] size[%d] overflow", addr, size); + return 0; + } + + if (addr < sInfo.protectAddr || addr >= sInfo.protectAddr + sInfo.protectSize) { + return 0; + } + + if (addrEnd > sInfo.protectAddr + sInfo.protectSize) { + FATAL_ERROR("addr[0x%08x] size[%d] overflow protect", addr, size); + return 0; + } + + return 1; +} + +static uint8_t ReadFlash(HFlashAddr_t addr, void *data, uint32_t size) +{ + if (sInfo.read == NULL) { + FATAL_ERROR("read is null"); + return 0; + } + + uint8_t *dataPtr = (uint8_t *)data; + return sInfo.read(addr, dataPtr, size); +} + +static uint8_t EraseFlash(HFlashAddr_t addr) +{ + if (sInfo.erase == NULL) { + FATAL_ERROR("erase is null"); + return 0; + } + + return sInfo.erase(addr); +} + +static uint8_t WriteData(HFlashAddr_t addr, void *data, uint32_t size, void(*call)(void *dest, const void *src, uint16_t buffSize, void *userData), void *userData) +{ + if (sInfo.write == NULL) { + FATAL_ERROR("write is null"); + return 0; + } + + 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 (ReadFlash(adjustAddr, buff, HFLASH_BLOCK_SIZE) == 0) { + LogE("addr[0x%08x], read faild", adjustAddr); + goto _flashError; + } + + if (EraseFlash(adjustAddr) == 0) { + LogE("addr[0x%08x], erase faild", adjustAddr); + goto _flashError; + } + + call(buff + offset, dataPtr, remain, userData); + // memcpy(buff + offset, dataPtr, remain); + if (sInfo.write(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 (EraseFlash(adjustAddr) == 0) { + LogE("addr[0x%08x], erase faild", adjustAddr); + goto _flashError; + } + + call(buff, dataPtr, HFLASH_BLOCK_SIZE, userData); + // memcpy(buff, dataPtr, HFLASH_BLOCK_SIZE); + if (sInfo.write(adjustAddr, buff, HFLASH_BLOCK_SIZE) == 0) { + LogE("addr[0x%08x], write faild", adjustAddr); + goto _flashError; + } + } + + // 操作最后一个未对齐的块 + if (size) { + if (ReadFlash(adjustAddr, buff, HFLASH_BLOCK_SIZE) == 0) { + LogE("addr[0x%08x], read faild", adjustAddr); + goto _flashError; + } + + if (EraseFlash(adjustAddr) == 0) { + LogE("addr[0x%08x], erase faild", adjustAddr); + goto _flashError; + } + + call(buff, dataPtr, size, userData); + // memcpy(buff, dataPtr, size); + if (sInfo.write(adjustAddr, buff, HFLASH_BLOCK_SIZE) == 0) { + LogE("addr[0x%08x], write faild", adjustAddr); + goto _flashError; + } + } + + result = 1; + +_flashError: + HFLASH_FREE(buff); + return result; +} + +static void _WriteFlashHelper(void *dest, const void *src, uint16_t buffSize, void *userData) +{ + (void)userData; + memcpy(dest, src, buffSize); +} + +static uint8_t WriteFlash(HFlashAddr_t addr, void *data, uint32_t size) +{ + return WriteData(addr, data, size, _WriteFlashHelper, NULL); +#if 0 + if (sInfo.write == NULL) { + FATAL_ERROR("write is null"); + return 0; + } + + 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 (ReadFlash(adjustAddr, buff, HFLASH_BLOCK_SIZE) == 0) { + LogE("addr[0x%08x], read faild", adjustAddr); + goto _flashError; + } + + if (EraseFlash(adjustAddr) == 0) { + LogE("addr[0x%08x], erase faild", adjustAddr); + goto _flashError; + } + + memcpy(buff + offset, dataPtr, remain); + if (sInfo.write(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 (EraseFlash(adjustAddr) == 0) { + LogE("addr[0x%08x], erase faild", adjustAddr); + goto _flashError; + } + + memcpy(buff, dataPtr, HFLASH_BLOCK_SIZE); + if (sInfo.write(adjustAddr, buff, HFLASH_BLOCK_SIZE) == 0) { + LogE("addr[0x%08x], write faild", adjustAddr); + goto _flashError; + } + } + + // 操作最后一个未对齐的块 + if (size) { + if (ReadFlash(adjustAddr, buff, HFLASH_BLOCK_SIZE) == 0) { + LogE("addr[0x%08x], read faild", adjustAddr); + goto _flashError; + } + + if (EraseFlash(adjustAddr) == 0) { + LogE("addr[0x%08x], erase faild", adjustAddr); + goto _flashError; + } + + memcpy(buff, dataPtr, size); + if (sInfo.write(adjustAddr, buff, HFLASH_BLOCK_SIZE) == 0) { + LogE("addr[0x%08x], write faild", adjustAddr); + goto _flashError; + } + } + + result = 1; + +_flashError: + HFLASH_FREE(buff); + return result; +#endif +} + +static void _WriteFalshValueHelper(void *dest, const void *src, uint16_t size, void *userData) +{ + uint8_t *value = (uint8_t *)userData; + memset(dest, *value, size); +} + +static uint8_t WriteFlashValue(uint32_t addr, uint32_t size, uint8_t value) +{ + return WriteData(addr, NULL, size, _WriteFalshValueHelper, &value); +} + +static void SyncBackup() +{ + // 需要备份的数据为空, 说明是二次调用, 上次已经同步了 + if (HVectorEmpty(sNeedBackupOffset) && sPageInfo.needBackupPage == 0) { + return ; + } + + for (uint16_t i = 0; i < HVectorGetUseLen(sNeedBackupOffset); ++i) { + const uint32_t addr = HVectorGetData(sNeedBackupOffset, i); + const uint32_t destAddr = sInfo.protectAddr + (addr - sInfo.pageAddr); + RestoreBackup(addr, destAddr, HFLASH_BLOCK_SIZE); + } + + HVectorClear(sNeedBackupOffset); + + // 备份页表数据 + RestoreBackup(sInfo.pageAddr, sInfo.pageBackupAddr, sInfo.pageSize); + sPageInfo.needBackupPage = 0; +} + +static void _AddBackupAddr(uint32_t addr) +{ + const HVectorLenType index = HVectorFindData(sNeedBackupOffset, addr); + if (index == HVECTOR_ERROR) { + return ; + } + + if (HVectorAddData(sNeedBackupOffset, addr)) { + return ; + } + + // 添加数据失败, 缓存已满, 需要先同步再添加 + SyncBackup(); + if (HVectorAddData(sNeedBackupOffset, addr) == 0) { + LogE("add wait sync addr[0x%08x], faild", addr); + } +} + +static void AddBackupAddr(uint32_t addr, uint32_t size) +{ + if (IsProtect(addr, size) == 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); + size -= remain; + adjustAddr += HFLASH_BLOCK_SIZE; + for (; size >= HFLASH_BLOCK_SIZE; adjustAddr += HFLASH_BLOCK_SIZE, size -= HFLASH_BLOCK_SIZE) { + _AddBackupAddr(adjustAddr); + } + + if (size) { + _AddBackupAddr(adjustAddr); + } +} + + +static uint32_t GetFlashCrc32(HFlashAddr_t addr, uint32_t size) +{ + if (size == 0) { + return 0xFFFFFFFF; + } + + HSCrc32Reset(); + 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 = FLASH_MIN(uint32_t, size - i, HFLASH_BLOCK_SIZE); + if (ReadFlash(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); + return HSCrc32Get(); +} + +static uint8_t RestoreBackup(HFlashAddr_t srcAddr, HFlashAddr_t dstAddr, uint32_t size) +{ + uint8_t *buff = (uint8_t *)HFLASH_MALLOC(HFLASH_BLOCK_SIZE); + if (buff == NULL) { + LogE("addr[0x%08x], write size[%d] malloc faild", srcAddr, size); + return 0; + } + + uint8_t result = 0; + uint32_t i = 0; + uint32_t remain = 0; + for (; i < size; i += HFLASH_BLOCK_SIZE) { + remain = FLASH_MIN(uint32_t, size - i, HFLASH_BLOCK_SIZE); + result = result || ReadFlash(srcAddr + i, buff, remain) == 0; + result = result || WriteFlash(dstAddr + i, buff, remain) == 0; + + if (result) { + LogE("read addr[0x%08x], write addr[0x%08x], write size[%d] faild", srcAddr + i, dstAddr + i, remain); + result = 0; + goto _FlashError; + } + } + + result = 1; +_FlashError: + HFLASH_FREE(buff); + LogD("Restore srcAddr[0x%08x], dstAddr[0x%08x], size[%d], result[%d]", srcAddr, dstAddr, size, !result); + return result; +} + +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 uint8_t RestorePage(uint32_t index) +{ + if (index >= sPageInfo.useNum) { + LogE("index[%d][%d] overflow", index, sPageInfo.useNum); + return 0; + } + + const HFlashAddr_t srcAddr = AdjustPageAddrOffset(sInfo.pageBackupAddr, index); + const HFlashAddr_t dstAddr = AdjustPageAddrOffset(sInfo.pageAddr, index); + return RestoreBackup(srcAddr, dstAddr, sizeof(HFlashPageInfo)); +} + +static void UpdatePageInfo() +{ + sPageInfo.crc32 = GetFlashCrc32(AdjustPageAddr(sInfo.pageAddr), AdjustPageByte(sPageInfo.useNum)); + WriteFlash(sInfo.pageAddr, &sPageInfo, sizeof(sPageInfo)); + + sPageInfo.needBackupPage = 1; +} + +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); + ReadFlash(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)); + + UpdatePageInfo(); +} + +/// 检查是否重叠, 重叠返回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 (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; + } + + const uint32_t pageNum = FLASH_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 = FLASH_MIN(uint32_t, sPageInfo.useNum - i, pageNum); + if (ReadFlash(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; +} + +static uint8_t _CreatePageInfoHelper(uint32_t index, HFlashPageInfo *info, void *userData) +{ + HFlashPageInfo *cache = (HFlashPageInfo *)userData; + return IsOverLap(info->addr, info->size, cache->addr, cache->size); +} + +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; + } + + if (sPageInfo.useNum >= sPageInfo.pageNum) { + FATAL_ERROR("page table is full"); + return 0; + } + + // 写入新页表 + const uint32_t 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) +{ + 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; + for (uint16_t i = 0; i < sInfo.pageCacheUseNum; ++i) { + currMin = FLASH_MIN(uint8_t, currMin, sInfo.pageCache[i].heat); + if (sInfo.pageCache[i].info.addr != addr) { + continue; + } + + sInfo.pageCache[i].heat = FLASH_MIN(uint8_t, sInfo.pageCache[i].heat + 1, ((1 << 5) - 1)); + return &sInfo.pageCache[i]; + } + + // 没有找到, 先降低温度 + if (sInfo.pageCacheUseNum && currMin > 0) { + for (uint16_t i = 0; i < sInfo.pageCacheUseNum; ++i) { + sInfo.pageCache[i].heat -= currMin; + } + } + + // 查找到了就直接替换最后面的就行 + HFlashCacheInfo cache; + memset(&cache, 0, sizeof(HFlashCacheInfo)); + cache.info.addr = addr; + if (ScanPage(_FindCacheHelper, &cache)) { + const uint16_t index = sInfo.pageCacheUseNum; + if (sInfo.pageCacheUseNum < sInfo.pageCacheSize) { + ++sInfo.pageCacheUseNum; + } + + memcpy(&sInfo.pageCache[index], &cache, sizeof(HFlashCacheInfo)); + return &sInfo.pageCache[index]; + } + + return NULL; +} + +void HFlashInitCallback(HFlashReadCallback read, HFlashWriteCallback write, HFlashEraseCallback erase) +{ + sInfo.read = read; + sInfo.write = write; + sInfo.erase = erase; +} + +void HFlashSetPageCache(HFlashCacheInfo *pageInfo, uint16_t size) +{ + sInfo.pageCache = pageInfo; + sInfo.pageCacheSize = size; +} + +void HFlashSetPageAddr(HFlashAddr_t addr, uint32_t size) +{ + sInfo.pageAddr = addr; + sInfo.pageSize = size; +} + +void HFlashSetPageBackupAddr(HFlashAddr_t addr, uint32_t size) +{ + if (sInfo.pageSize != size) { + FATAL_ERROR("page size not match[%d][%d]", sInfo.pageSize, size); + return ; + } + + sInfo.pageBackupAddr = addr; + sInfo.pageSize = size; +} + +void HFlashProtectAddr(HFlashAddr_t addr, uint32_t size) +{ + sInfo.protectAddr = addr; + sInfo.protectSize = size; +} + +void HFlashProtectBackupAddr(HFlashAddr_t addr, uint32_t size) +{ + if (sInfo.protectSize != size) { + FATAL_ERROR("protect size not match[%d][%d]", sInfo.protectSize, size); + return ; + } + + sInfo.protectBackupAddr = addr; + sInfo.protectSize = size; +} + +void HFlashInitCheck() +{ + if (sInfo.pageCache == NULL || sInfo.pageCacheSize == 0) { + FATAL_ERROR("pageCache is null"); + return ; + } + + // 检查页表地址有没有和备份地址重叠问题 + if (IsOverLap(sInfo.pageAddr, sInfo.pageSize, sInfo.pageBackupAddr, sInfo.pageSize)) { + FATAL_ERROR("page table and backup table is overlap"); + return ; + } + + const uint32_t num = sInfo.pageSize / sizeof(HFlashPageInfo); + do { + if (ReadFlash(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 (ReadFlash(sInfo.pageBackupAddr, sPageInfo.reverse, sizeof(sPageInfo)) == 0) { + LogE("Read backup page table[0x%08x] faild", sInfo.pageBackupAddr); + break; + } + + invalid = sPageInfo.pageNum > num; + invalid = invalid || sPageInfo.useNum > num; + invalid = invalid || sPageInfo.useNum > sPageInfo.pageNum; + invalid = invalid || GetFlashCrc32(AdjustPageAddr(sInfo.pageBackupAddr), AdjustPageByte(sPageInfo.useNum)) != sPageInfo.crc32; + if (invalid) { + // 备份也无效, 首次创建, 去初始化数据 + LogD("backup page table is invalid, init data"); + break; + } + + // 备份校验通过, 恢复备份数据 + RestoreBackup(sInfo.pageBackupAddr, sInfo.pageAddr, sPageInfo.useNum); + return ; + } while (0); + + memset(sPageInfo.reverse, 0, sizeof(sPageInfo)); + sPageInfo.pageNum = num; +} + +void HFlashRegister(HFlashAddr_t addr, uint32_t size) +{ + if (IS_NOT_4(size)) { + FATAL_ERROR("size[%d] not align 4", 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); + } + + sPageInfo.needBackupPage = 1; + cache = FindCache(addr); + RestoreBackup(sInfo.protectAddr, sInfo.protectBackupAddr, sInfo.protectSize); + return ; + } + + // 检查是否在保护区域, 不是保护区域不需要检查crc校验 + if (IsProtect(addr, size) == 0) { + return ; + } + + // 检查保护区域的crc是否相同 + if (GetFlashCrc32(addr, size) == cache->info.crc32) { + return ; + } + + // 先恢复内容区域 + LogD("addr[0x%08x] size[%d] crc32 not match, start restore", addr, size); + RestoreBackup(sInfo.protectBackupAddr + (cache->info.addr - sInfo.protectAddr), cache->info.addr, cache->info.size); + + // 如果恢复后还校验失败, 那就恢复对应页表 + const uint32_t contentCrc = GetFlashCrc32(cache->info.addr, cache->info.size); + 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); + if (contentCrc == cache->info.crc32) { + return ; + } + + // 恢复后数据还是错误的, 需要将页表数据使用长度修正0, 避免异常数据导致程序异常 + LogE("addr[0x%08x] size[%d] crc32 not match", cache->info.addr, cache->info.size); + cache->info.useSize = 0; + cache->info.crc32 = GetFlashCrc32(cache->info.addr, cache->info.useSize); + WritePage(cache->pos, &cache->info); +} + +void HFlashWrite(HFlashAddr_t addr, void *data, uint32_t size) +{ + // 检查是否存在致命性错误, 使用的地址不在注册页表中 + HFlashCacheInfo *cache = FindCache(addr); + if (cache == NULL) { + FATAL_ERROR("addr[0x%08x] not register", addr); + return ; + } + + // 检查写入数据大小是否超出注册提供的大小范围 + if (cache->info.size < size) { + FATAL_ERROR("addr[0x%08x] size[%d] overflow", addr, size); + return ; + } + + // 更新使用长度 + if (cache->info.useSize < size) { + cache->info.useSize = size; + } + + // 更新crc, 写入数据后再更新页表 + HSCrc32Reset(); + HSCrc32Update((uint8_t *)data, size); + cache->info.crc32 = HSCrc32Get(); + ++cache->info.modifyCount; + + // 检查是否在保护区域, 需要的话需要写入等待备份 + if (IsProtect(addr, size)) { + AddBackupAddr(addr, size); + } + + WriteFlash(addr, data, size); + WritePage(cache->pos, &cache->info); +} + diff --git a/src/HRingBuffer.c b/src/HRingBuffer.c index 6f5ad96..a81790a 100644 --- a/src/HRingBuffer.c +++ b/src/HRingBuffer.c @@ -90,17 +90,14 @@ static inline uint8_t IsRingBufferFull(const HRingBufferType *ringBuffer) { InitRingBuffer((HRingBufferType *)ringBuffer); const _HRingBufferBase *base = (const _HRingBufferBase *)ringBuffer; - return (base->flag & kHRingBufferFull) == kHRingBufferFull; + return !!(base->flag & kHRingBufferFull); } static inline void SetRingBufferFull(HRingBufferType *ringBuffer, uint8_t full) { InitRingBuffer((HRingBufferType *)ringBuffer); _HRingBufferBase *base = (_HRingBufferBase *)ringBuffer; - if (full) { - base->flag |= kHRingBufferFull; - } else { - base->flag &= ~kHRingBufferFull; - } + const uint8_t f = -(uint8_t)(!!full); + base->flag = (base->flag & ~kHRingBufferFull) | (f & kHRingBufferFull); } static void AdjustReadPos(HRingBufferType *ringBuffer, HRingBufferLenType pos) {