1. 完善初版HFlashServer
This commit is contained in:
parent
019a0604d0
commit
ea96363aff
141
include/HFlashServer.h
Normal file
141
include/HFlashServer.h
Normal file
@ -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 <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
///< 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__
|
||||
817
src/HFlashServer.c
Normal file
817
src/HFlashServer.c
Normal file
@ -0,0 +1,817 @@
|
||||
|
||||
|
||||
#include "HFlashServer.h"
|
||||
#include "HDLog.h"
|
||||
#include "HVector.h"
|
||||
|
||||
|
||||
#if 1
|
||||
#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 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);
|
||||
}
|
||||
|
||||
@ -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) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user