1. 提升Flash模块
This commit is contained in:
parent
fd76d9f346
commit
599e255653
@ -33,6 +33,11 @@
|
||||
#define USE_RTOS_LOG_LOCK (0)
|
||||
#endif
|
||||
|
||||
// 是否使用HShell
|
||||
#ifndef HDLOG_USE_HSHELL
|
||||
#define HDLOG_USE_HSHELL (1)
|
||||
#endif
|
||||
|
||||
// 标准日志输出
|
||||
#define _LogDExtLevel(level, format, ...) HDLogOut(1, level, __FILE__, __func__, __LINE__, format, ##__VA_ARGS__)
|
||||
#define _LogDLevel(level, format, ...) HDLogOut(0, level, __FILE__, __func__, __LINE__, format, ##__VA_ARGS__)
|
||||
|
||||
@ -11,6 +11,11 @@
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
// 是否使用 hshell
|
||||
#ifndef HFLASH_USE_HSHELL
|
||||
#define HFLASH_USE_HSHELL 1
|
||||
#endif
|
||||
|
||||
// 使用定时器任务ID
|
||||
#ifndef HFLASH_TIMER_ID
|
||||
#define HFLASH_TIMER_ID 0
|
||||
@ -25,13 +30,17 @@ enum eHFlashMemIO
|
||||
};
|
||||
|
||||
///< 内存缓存页, 配置需和 (memSize / 4096) 大小一致
|
||||
///< 这里不再使用 heat 衰减, 改成 referenced + probation 的二次机会策略
|
||||
///< 旧方案需要周期性降温, 小缓存且写入频繁时维护成本高, 也更容易把一次性读页长期留在缓存里
|
||||
typedef struct HFlashMemCache
|
||||
{
|
||||
uint32_t addr; ///< 地址
|
||||
uint16_t offset; ///< 内存偏移
|
||||
uint16_t eraseStatus : 2; ///< 擦除状态
|
||||
uint16_t isDirty : 1; ///< 是否脏页
|
||||
uint16_t heat : 5; ///< 热度优先级
|
||||
uint16_t referenced : 1; ///< 最近是否访问过, 仅在命中/装载时置1, 淘汰扫描时清0给第二次机会
|
||||
uint16_t probation : 1; ///< 新进入缓存的试用页, 只有再次命中后才转正式页, 这样能优先淘汰一次性访问
|
||||
uint16_t reserved : 11;
|
||||
} HFlashMemCache;
|
||||
|
||||
///< 内存操作, 回调返回0表示失败
|
||||
@ -42,14 +51,16 @@ typedef struct HFlashMemOpts
|
||||
uint8_t (*ioctl)(uint32_t addr, uint32_t cmd, void *arg); ///< 控制Flash, 需要外部实现以上eHFlashMemIO指令
|
||||
uint8_t *mem; ///< Flash映射内存, 需要4k倍数
|
||||
HFlashMemCache *cache; ///< 内存缓存
|
||||
uint16_t memSize; ///< Flash映射内存大小
|
||||
uint16_t cacheSize; ///< 内存缓存大小
|
||||
uint32_t memSize; ///< Flash映射内存大小, 改成32位后可避免映射区超过64KB时页数计算溢出
|
||||
uint32_t cacheSize; ///< 内存缓存页数量, 需要始终等于 memSize / 4096, 否则 offset 映射会错位
|
||||
uint32_t flashSize; ///< Flash大小
|
||||
} HFlashMemOpts;
|
||||
|
||||
/**
|
||||
* @brief 初始化Flash内存映射
|
||||
* @param opts 内存操作信息
|
||||
* mem/cache 内存由外部分配并长期持有, 初始化不会复制这两块内存
|
||||
* cacheSize 必须和 memSize / 4096 完全一致, 因为每个 cache 结构固定对应一个4K映射页
|
||||
*/
|
||||
void HFlashMemInit(HFlashMemOpts *opts);
|
||||
|
||||
|
||||
@ -12,6 +12,11 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// 使用HShell
|
||||
#ifndef HFLASH_USE_HSHELL
|
||||
#define HFLASH_USE_HSHELL 1
|
||||
#endif
|
||||
|
||||
///< 使用Flash内存映射功能
|
||||
#ifndef HFLASH_NOT_USE_FLASH_MEM
|
||||
#define HFLASH_USE_FLASH_MEM
|
||||
@ -85,6 +90,12 @@ typedef union HFlashPageInfo {
|
||||
};
|
||||
} HFlashPageInfo;
|
||||
|
||||
typedef struct HFlashProtectInfo {
|
||||
HFlashAddr_t addr; ///< 保护区地址
|
||||
uint32_t size; ///< 保护区大小
|
||||
HFlashAddr_t backupAddr; ///< 保护区备份地址
|
||||
} HFlashProtectInfo;
|
||||
|
||||
typedef struct HFlashCacheInfo {
|
||||
HFlashPageInfo info; ///< 页表信息
|
||||
uint32_t pos : 19; ///< 存储页表信息的位置
|
||||
@ -149,6 +160,14 @@ uint16_t HFlashGetVersion(HFlashAddr_t addr, HFlashVersionInfo *info);
|
||||
*/
|
||||
void HFlashSetPageCache(HFlashCacheInfo *pageInfo, uint16_t size);
|
||||
|
||||
/**
|
||||
* @brief HFlashSetProtectCache 设置保护区描述缓存, 内部不构建内存, 由外部分配
|
||||
* 需要在设置保护地址前调用
|
||||
* @param protectInfo 保护区描述缓存
|
||||
* @param size 大小
|
||||
*/
|
||||
void HFlashSetProtectCache(HFlashProtectInfo *protectInfo, uint16_t size);
|
||||
|
||||
/**
|
||||
* @brief HFlashSetPageAddr 设置页表地址
|
||||
* @param addr 地址
|
||||
@ -158,24 +177,31 @@ void HFlashSetPageAddr(HFlashAddr_t addr, uint32_t size);
|
||||
|
||||
/**
|
||||
* @brief HFlashSetPageBackupAddr 设置页表备份地址, 需要先设置页表再设置备份
|
||||
* 页表备份地址独立存储, 大小必须和页表地址大小相同
|
||||
* @param addr 地址
|
||||
* @param size 大小, 必须和页表地址大小相同
|
||||
* @param size 大小, 需要4K对齐
|
||||
*/
|
||||
void HFlashSetPageBackupAddr(HFlashAddr_t addr, uint32_t size);
|
||||
|
||||
/**
|
||||
* @brief HFlashSetProtectAddr 设置保护地址, 内部会使用双备份区域
|
||||
* @param addr 地址
|
||||
* @param size 大小
|
||||
* @brief HFlashClearProtectAddr 清空保护地址配置和对应备份映射
|
||||
*/
|
||||
void HFlashSetProtectAddr(HFlashAddr_t addr, uint32_t size);
|
||||
void HFlashClearProtectAddr();
|
||||
|
||||
/**
|
||||
* @brief HFlashSetProtectBackupAddr 设置保护备份地址, 需要先设置保护地址再设置备份
|
||||
* @brief HFlashAddProtectAddr 添加保护地址, 可多次调用追加多个保护区域
|
||||
* 保护区描述内存由 HFlashSetProtectCache 外部提供
|
||||
* @param addr 地址
|
||||
* @param size 大小, 必须和保护地址大小相同
|
||||
* @param size 大小
|
||||
* @param backupAddr 备份地址, 会按保护区大小自动建立一条连续备份映射
|
||||
*/
|
||||
void HFlashSetProtectBackupAddr(HFlashAddr_t addr, uint32_t size);
|
||||
void HFlashAddProtectAddr(HFlashAddr_t addr, uint32_t size, HFlashAddr_t backupAddr);
|
||||
|
||||
/**
|
||||
* @brief HFlashDelProtectAddr 删除保护地址和对应备份映射
|
||||
* @param addr 地址
|
||||
*/
|
||||
void HFlashDelProtectAddr(HFlashAddr_t addr);
|
||||
|
||||
/**
|
||||
* @brief HFlashInitCheck 在HFlashRegister前需要初始化检查, 用于检查页表是否可用, 不可用则需要初始化
|
||||
|
||||
11
src/HDLog.c
11
src/HDLog.c
@ -2,12 +2,15 @@
|
||||
|
||||
#include "HDLog.h"
|
||||
#include "HBit.h"
|
||||
#include "HShellLex.h"
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#if HDLOG_USE_HSHELL
|
||||
#include "HShellLex.h"
|
||||
#endif
|
||||
|
||||
#if USE_RTOS_LOG_LOCK
|
||||
#include "FreeRTOS.h"
|
||||
#include "semphr.h"
|
||||
@ -39,6 +42,7 @@ typedef struct HDLogFpgaCheckInfo
|
||||
#define CHECK_FPGA_INFO_ID (100)
|
||||
#endif
|
||||
|
||||
#if HDLOG_USE_HSHELL
|
||||
static HShellMatch sLogMatch[] = {
|
||||
HSHELL_MATCH_ITEM(kLogLevelSwitch, "log"),
|
||||
HSHELL_MATCH_ITEM(kLogLevelColor, "logColor"),
|
||||
@ -54,6 +58,7 @@ static HShellMatch sLogMatch[] = {
|
||||
HSHELL_MATCH_ITEM(CHECK_FPGA_INFO_ID + 1, "clearCheckFpga"),
|
||||
#endif
|
||||
};
|
||||
#endif
|
||||
|
||||
///< 日志级别
|
||||
static HBIT_DEFINE(sLogItem, kLogLevelMax);
|
||||
@ -184,6 +189,7 @@ static void LogHex(const uint8_t *data, int len, uint8_t checkPrint, uint8_t log
|
||||
}
|
||||
}
|
||||
|
||||
#if HDLOG_USE_HSHELL
|
||||
static void LogShell(HSHELL_FUNC_ARGS)
|
||||
{
|
||||
uint32_t arg1 = 0;
|
||||
@ -211,6 +217,7 @@ static void LogShell(HSHELL_FUNC_ARGS)
|
||||
sFlashCall(1, key, arg1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void HDLogSetOptFlashCall(HDLogFlashOpt_t call)
|
||||
{
|
||||
@ -234,7 +241,9 @@ void HDLogOptFlashInit()
|
||||
void HDLogInit(uint32_t (*getTime)())
|
||||
{
|
||||
sGetTime = getTime;
|
||||
#if HDLOG_USE_HSHELL
|
||||
HSHellRegister(sLogMatch, sizeof(sLogMatch) / sizeof(HShellMatch), LogShell, 1);
|
||||
#endif
|
||||
if (sFlashCall == NULL)
|
||||
{
|
||||
HBitSet(sLogItem, kLogLevelSwitch, 0);
|
||||
|
||||
595
src/HFlashMem.c
595
src/HFlashMem.c
@ -3,34 +3,31 @@
|
||||
#include "HDLog.h"
|
||||
#include "HTimer.h"
|
||||
|
||||
#ifndef USE_STD_MEM
|
||||
#if HFLASH_USE_HSHELL
|
||||
#include "HShellLex.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef USE_STD_MEM
|
||||
#define FATAL_ERROR(format, ...) LogE(format, ##__VA_ARGS__);
|
||||
#else
|
||||
#include "HShellLex.h"
|
||||
#elif HFLASH_USE_HSHELL
|
||||
#define FATAL_ERROR(format, ...) while (1) { LogE(format, ##__VA_ARGS__); HShellRun(); };
|
||||
#else
|
||||
#define FATAL_ERROR(format, ...) while (1) { LogE(format, ##__VA_ARGS__); };
|
||||
#endif
|
||||
|
||||
// flash块大小
|
||||
#define HFLASH_BLOCK_SIZE (4096)
|
||||
|
||||
// 调度热度时间
|
||||
#define HEAT_TIME_MS (1000)
|
||||
|
||||
// 是否对齐页
|
||||
#define IS_4K(size) ((size & (HFLASH_BLOCK_SIZE - 1)) == 0)
|
||||
|
||||
// 最大热度
|
||||
#define MAX_HEAT ((1 << 5) - 1)
|
||||
|
||||
// 写转读增加热度
|
||||
#define WRITE_CONV_READ_ADD_HEAT (2)
|
||||
|
||||
// 读最小热度
|
||||
#define READ_MIN_HEAT (0)
|
||||
|
||||
// 快速最小值
|
||||
#define FAST_MIN(type, a, b) ((b) ^ (((a) ^ (b)) & (-(type)((a) < (b)))))
|
||||
// 这里允许少量读 miss 直接绕过缓存
|
||||
// 当缓存已被脏页占满时, 如果每次只读 miss 都强制抢占缓存, 会触发同步刷写, 小缓存场景抖动很大
|
||||
// 因此只有同一页连续被直读多次, 才认为它值得挤进缓存
|
||||
// 全脏页下, 同一页连续直读达到该次数后才提升进缓存
|
||||
#define BYPASS_PROMOTE_THRESHOLD (3)
|
||||
|
||||
enum eErase
|
||||
{
|
||||
@ -41,9 +38,13 @@ enum eErase
|
||||
|
||||
struct Info
|
||||
{
|
||||
uint32_t currHeatTime; ///< 当前热度时间, 用于计算下一次热度下降
|
||||
uint32_t bypassAddr; ///< 全脏页读 miss 时, 最近一次直读页地址
|
||||
uint16_t useNum; ///< 缓存已使用数量
|
||||
uint16_t readClockHand; ///< 读页淘汰时的时钟指针
|
||||
uint16_t dirtyClockHand; ///< 脏页回收时的时钟指针
|
||||
uint8_t bypassCount; ///< 当前直读页连续命中次数
|
||||
uint16_t needWaitErase : 1; ///< 用于判断是否在擦除
|
||||
uint16_t bypassValid : 1; ///< 最近一次直读页地址是否有效
|
||||
};
|
||||
|
||||
// 内存操作
|
||||
@ -55,6 +56,9 @@ static struct Info sInfo;
|
||||
// 检查定时器
|
||||
static HTimer_t sCheckTimer = HTIMER_INVALID;
|
||||
|
||||
static void WatiErase();
|
||||
static void CheckSyncCache();
|
||||
|
||||
// 对齐页地址, 向下取整
|
||||
static inline uint32_t Align4K(uint32_t addr) {
|
||||
return addr & ~(HFLASH_BLOCK_SIZE - 1);
|
||||
@ -65,6 +69,110 @@ static inline uint8_t *GetMMap(uint16_t offset) {
|
||||
return (uint8_t *)sOpts->mem + offset * HFLASH_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
static inline uint8_t IsReusableCleanCache(const HFlashMemCache *cache)
|
||||
{
|
||||
return cache->isDirty == 0 && cache->eraseStatus == kEraseWait;
|
||||
}
|
||||
|
||||
static void TouchCache(HFlashMemCache *cache)
|
||||
{
|
||||
// 这里同时清 probation
|
||||
// 新页首次装入时先标记为“试用页”, 只有再次命中才认为它真的是热点, 避免一次性读页长期占坑
|
||||
cache->referenced = 1;
|
||||
cache->probation = 0;
|
||||
}
|
||||
|
||||
static void InitCache(HFlashMemCache *cache, uint16_t index, uint32_t addr, uint8_t probation)
|
||||
{
|
||||
memset(cache, 0, sizeof(HFlashMemCache));
|
||||
cache->addr = addr;
|
||||
cache->offset = index;
|
||||
cache->referenced = 1;
|
||||
cache->probation = probation;
|
||||
}
|
||||
|
||||
static void MarkCleanCache(HFlashMemCache *cache)
|
||||
{
|
||||
// 脏页刷回后会被重新当作试用页
|
||||
// 刚完成回写只代表它“被写过”, 不代表后续仍然高频访问, 立即降为 probation 能避免旧脏页长期压制新页
|
||||
cache->isDirty = 0;
|
||||
cache->eraseStatus = kEraseWait;
|
||||
cache->referenced = 0;
|
||||
cache->probation = 1;
|
||||
}
|
||||
|
||||
static void ClearBypassAddr(uint32_t addr)
|
||||
{
|
||||
if (sInfo.bypassValid && sInfo.bypassAddr == addr) {
|
||||
sInfo.bypassValid = 0;
|
||||
sInfo.bypassCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void RecordBypassAddr(uint32_t addr)
|
||||
{
|
||||
if (sInfo.bypassValid && sInfo.bypassAddr == addr) {
|
||||
if (sInfo.bypassCount < BYPASS_PROMOTE_THRESHOLD) {
|
||||
++sInfo.bypassCount;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
sInfo.bypassAddr = addr;
|
||||
sInfo.bypassValid = 1;
|
||||
sInfo.bypassCount = 1;
|
||||
}
|
||||
|
||||
static uint8_t HasDirtyCache()
|
||||
{
|
||||
for (uint16_t i = 0; i < sInfo.useNum; ++i) {
|
||||
if (sOpts->cache[i].isDirty) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static HFlashMemCache *FindCacheByAddr(uint32_t addr)
|
||||
{
|
||||
for (uint16_t i = 0; i < sInfo.useNum; ++i) {
|
||||
if (addr == sOpts->cache[i].addr) {
|
||||
return sOpts->cache + i;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static uint8_t LoadCachePage(HFlashMemCache *cache, uint32_t addr)
|
||||
{
|
||||
WatiErase();
|
||||
if (sOpts->read(addr, GetMMap(cache->offset), HFLASH_BLOCK_SIZE) == 0) {
|
||||
LogE("addr[0x%08x], read faild", addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static uint8_t SyncDirtyCache(HFlashMemCache *cache)
|
||||
{
|
||||
if (cache == NULL || cache->isDirty == 0) {
|
||||
return cache != NULL;
|
||||
}
|
||||
|
||||
WatiErase();
|
||||
sOpts->ioctl(cache->addr, kHFlashMemIOSyncErase, NULL);
|
||||
if (sOpts->write(cache->addr, GetMMap(cache->offset), HFLASH_BLOCK_SIZE) == 0) {
|
||||
LogE("addr[0x%08x], write faild", cache->addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
MarkCleanCache(cache);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void WatiErase()
|
||||
{
|
||||
// 如果存在异步等待擦除的, 先等擦除完成
|
||||
@ -90,66 +198,145 @@ static void SyncCache()
|
||||
}
|
||||
|
||||
LogD("Sync[%d], addr[0x%08x], offset[%d]", i, sOpts->cache[i].addr, sOpts->cache[i].offset);
|
||||
sOpts->ioctl(sOpts->cache[i].addr, kHFlashMemIOSyncErase, NULL);
|
||||
if (sOpts->write(sOpts->cache[i].addr, GetMMap(i), HFLASH_BLOCK_SIZE) == 0) {
|
||||
LogD("Sync[%d], addr[0x%08x], offset[%d] faild", i, sOpts->cache[i].addr, sOpts->cache[i].offset);
|
||||
--i;
|
||||
continue;
|
||||
if (SyncDirtyCache(sOpts->cache + i) == 0) {
|
||||
LogE("Sync[%d], addr[0x%08x], offset[%d] faild", i, sOpts->cache[i].addr, sOpts->cache[i].offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static HFlashMemCache *FindCleanVictim()
|
||||
{
|
||||
HFlashMemCache *fallback = NULL;
|
||||
if (sInfo.useNum == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// 两轮时钟扫描:
|
||||
// 1. referenced=1 的页先清位, 给第二次机会, 不立刻淘汰
|
||||
// 2. 优先淘汰 probation 页, 因为它们还没被二次命中过, 更可能只是一次性访问
|
||||
// 3. 如果没有 probation 页, 再回退到普通 clean 页
|
||||
for (uint8_t round = 0; round < 2; ++round) {
|
||||
for (uint16_t count = 0; count < sInfo.useNum; ++count) {
|
||||
const uint16_t index = sInfo.readClockHand;
|
||||
HFlashMemCache *cache = sOpts->cache + index;
|
||||
sInfo.readClockHand = (index + 1) % sInfo.useNum;
|
||||
if (IsReusableCleanCache(cache) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cache->referenced) {
|
||||
cache->referenced = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cache->probation) {
|
||||
return cache;
|
||||
}
|
||||
|
||||
fallback = cache;
|
||||
}
|
||||
|
||||
sOpts->cache[i].isDirty = 0;
|
||||
sOpts->cache[i].eraseStatus = kEraseWait;
|
||||
|
||||
// 写入页转换空闲页, 热度持续增加
|
||||
sOpts->cache[i].heat = FAST_MIN(uint8_t, sOpts->cache[i].heat + WRITE_CONV_READ_ADD_HEAT, MAX_HEAT);
|
||||
if (fallback) {
|
||||
return fallback;
|
||||
}
|
||||
}
|
||||
|
||||
for (uint16_t i = 0; i < sInfo.useNum; ++i) {
|
||||
if (IsReusableCleanCache(sOpts->cache + i)) {
|
||||
return sOpts->cache + i;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static HFlashMemCache *FindDirtyVictim()
|
||||
{
|
||||
HFlashMemCache *fallback = NULL;
|
||||
if (sInfo.useNum == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// 脏页选择也走 clock, 不再依赖 heat
|
||||
// 这里只挑 eraseStatus=kEraseWait 的脏页, 避免和正在擦除或等待写回的页并发冲突
|
||||
// 当前底层 ioctl 的擦除状态是全局查询模型, 同一时刻只维护一个异步擦除流程更安全
|
||||
for (uint8_t round = 0; round < 2; ++round) {
|
||||
HFlashMemCache *candidate = NULL;
|
||||
for (uint16_t count = 0; count < sInfo.useNum; ++count) {
|
||||
const uint16_t index = sInfo.dirtyClockHand;
|
||||
HFlashMemCache *cache = sOpts->cache + index;
|
||||
sInfo.dirtyClockHand = (index + 1) % sInfo.useNum;
|
||||
if (cache->isDirty == 0 || cache->eraseStatus != kEraseWait) {
|
||||
continue;
|
||||
}
|
||||
|
||||
fallback = cache;
|
||||
|
||||
if (cache->referenced) {
|
||||
cache->referenced = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
candidate = cache;
|
||||
}
|
||||
|
||||
if (candidate) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
|
||||
return fallback;
|
||||
}
|
||||
|
||||
static void NotifyASyncErase()
|
||||
{
|
||||
for (uint16_t i = 0; i < sInfo.useNum; ++i) {
|
||||
if (sOpts->cache[i].isDirty == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
HFlashMemCache *cache = FindDirtyVictim();
|
||||
if (cache) {
|
||||
// 这里只发起一个异步擦除请求
|
||||
// CheckSyncCache 依赖 needWaitErase + eraseStatus 顺序推进状态机, 多个并发擦除会让状态归属变复杂
|
||||
sInfo.needWaitErase = 1;
|
||||
sOpts->cache[i].eraseStatus = kEraseStart;
|
||||
sOpts->ioctl(sOpts->cache[i].addr, kHFlashMemIOErase, NULL);
|
||||
break;
|
||||
cache->eraseStatus = kEraseStart;
|
||||
sOpts->ioctl(cache->addr, kHFlashMemIOErase, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void FastSyncCache()
|
||||
static void StartSyncCache()
|
||||
{
|
||||
WatiErase();
|
||||
for (uint16_t i = 0; i < sInfo.useNum; ++i) {
|
||||
// 存在空闲页, 可以立刻解除
|
||||
if (sOpts->cache[i].isDirty == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
LogD("FastSync[%d], addr[0x%08x], offset[%d]", i, sOpts->cache[i].addr, sOpts->cache[i].offset);
|
||||
sOpts->ioctl(sOpts->cache[i].addr, kHFlashMemIOSyncErase, NULL);
|
||||
if (sOpts->write(sOpts->cache[i].addr, GetMMap(i), HFLASH_BLOCK_SIZE) == 0) {
|
||||
LogD("FastSync[%d], addr[0x%08x], offset[%d] faild", i, sOpts->cache[i].addr, sOpts->cache[i].offset);
|
||||
--i;
|
||||
continue;
|
||||
}
|
||||
|
||||
sOpts->cache[i].isDirty = 0;
|
||||
sOpts->cache[i].eraseStatus = kEraseWait;
|
||||
|
||||
// 写入页转换空闲页, 热度持续增加
|
||||
sOpts->cache[i].heat = FAST_MIN(uint8_t, sOpts->cache[i].heat + WRITE_CONV_READ_ADD_HEAT, MAX_HEAT);
|
||||
break;
|
||||
if (HasDirtyCache() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
NotifyASyncErase();
|
||||
if (sCheckTimer != HTIMER_INVALID) {
|
||||
return;
|
||||
}
|
||||
|
||||
sCheckTimer = HTimerAdd(HFLASH_TIMER_ID, 0, CheckSyncCache, kHTimerLoop);
|
||||
}
|
||||
|
||||
static HFlashMemCache *ReclaimOneCleanCache()
|
||||
{
|
||||
HFlashMemCache *cache = FindCleanVictim();
|
||||
if (cache) {
|
||||
return cache;
|
||||
}
|
||||
|
||||
cache = FindDirtyVictim();
|
||||
if (cache == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// 这里退化成同步回收一个脏页
|
||||
// 写路径必须拿到可用 cache, 如果此时全是脏页, 只能牺牲一次阻塞把一个页刷回, 否则无法继续分配
|
||||
LogD("Reclaim addr[0x%08x], offset[%d]", cache->addr, cache->offset);
|
||||
if (SyncDirtyCache(cache) == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return cache;
|
||||
}
|
||||
|
||||
static void CheckSyncCache()
|
||||
{
|
||||
// 检查擦除是否完成
|
||||
uint8_t status = 0;
|
||||
if (sInfo.needWaitErase) {
|
||||
sOpts->ioctl(0, kHFlashMemIOCheckErase, &status);
|
||||
@ -158,63 +345,44 @@ static void CheckSyncCache()
|
||||
}
|
||||
|
||||
sInfo.needWaitErase = 0;
|
||||
for (uint16_t i = 0; i < sInfo.useNum; ++i) {
|
||||
if (sOpts->cache[i].eraseStatus == kEraseStart) {
|
||||
sOpts->cache[i].eraseStatus = kWaitWrite;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t needErase = sInfo.useNum;
|
||||
uint8_t heat = MAX_HEAT;
|
||||
uint8_t waitWrite = 0;
|
||||
// 这里先处理 kWaitWrite, 再决定是否继续提交新的擦除
|
||||
// 写回完成后才能把页重新放回 clean 集合, 否则 read/write 侧会一直看不到可回收页
|
||||
for (uint16_t i = 0; i < sInfo.useNum; ++i) {
|
||||
// 检查哪个页的异步擦除, 现在擦除完成
|
||||
if (sOpts->cache[i].eraseStatus == kEraseStart) {
|
||||
sOpts->cache[i].eraseStatus = kWaitWrite;
|
||||
}
|
||||
|
||||
waitWrite |= sOpts->cache[i].isDirty;
|
||||
// 寻找需要擦除的页
|
||||
if (sOpts->cache[i].isDirty && sOpts->cache[i].eraseStatus == kEraseWait) {
|
||||
// 查找最低热度的优先擦除, 方便低热度页转换空闲
|
||||
if (sOpts->cache[i].heat <= heat) {
|
||||
heat = sOpts->cache[i].heat;
|
||||
needErase = i;
|
||||
}
|
||||
}
|
||||
|
||||
// 如果不是脏页就跳过
|
||||
if (sOpts->cache[i].isDirty == 0) {
|
||||
HFlashMemCache *cache = sOpts->cache + i;
|
||||
if (cache->isDirty == 0 || cache->eraseStatus != kWaitWrite) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 检查Flash是否已经擦除完成
|
||||
if (sOpts->cache[i].eraseStatus != kWaitWrite) {
|
||||
if (sOpts->write(cache->addr, GetMMap(cache->offset), HFLASH_BLOCK_SIZE) == 0) {
|
||||
LogE("addr[0x%08x], write faild", cache->addr);
|
||||
cache->eraseStatus = kEraseWait;
|
||||
continue;
|
||||
}
|
||||
|
||||
// 如果写入失败, 则需要再次擦除重新写入
|
||||
if (sOpts->write(sOpts->cache[i].addr, GetMMap(i), HFLASH_BLOCK_SIZE) == 0) {
|
||||
LogE("addr[0x%08x], write faild", sOpts->cache[i].addr);
|
||||
sInfo.needWaitErase = 1;
|
||||
sOpts->cache[i].eraseStatus = kEraseWait;
|
||||
if (needErase == sInfo.useNum) {
|
||||
heat = sOpts->cache[i].heat;
|
||||
needErase = i;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
sOpts->cache[i].isDirty = 0;
|
||||
sOpts->cache[i].eraseStatus = kEraseWait;
|
||||
|
||||
// 写入页转换空闲页, 热度持续增加
|
||||
sOpts->cache[i].heat = FAST_MIN(uint8_t, sOpts->cache[i].heat + WRITE_CONV_READ_ADD_HEAT, MAX_HEAT);
|
||||
MarkCleanCache(cache);
|
||||
}
|
||||
|
||||
if (needErase != sInfo.useNum) {
|
||||
sInfo.needWaitErase = 1;
|
||||
sOpts->cache[needErase].eraseStatus = kEraseStart;
|
||||
sOpts->ioctl(sOpts->cache[needErase].addr, kHFlashMemIOErase, NULL);
|
||||
uint8_t hasPendingWrite = 0;
|
||||
for (uint16_t i = 0; i < sInfo.useNum; ++i) {
|
||||
if (sOpts->cache[i].isDirty && sOpts->cache[i].eraseStatus == kWaitWrite) {
|
||||
hasPendingWrite = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (sInfo.needWaitErase == 0 && waitWrite == 0) {
|
||||
if (sInfo.needWaitErase == 0 && hasPendingWrite == 0 && HasDirtyCache()) {
|
||||
NotifyASyncErase();
|
||||
}
|
||||
|
||||
if (sInfo.needWaitErase == 0 && hasPendingWrite == 0 && HasDirtyCache() == 0) {
|
||||
if (sCheckTimer != HTIMER_INVALID) {
|
||||
HTimerRemove(sCheckTimer);
|
||||
sCheckTimer = HTIMER_INVALID;
|
||||
@ -222,67 +390,7 @@ static void CheckSyncCache()
|
||||
}
|
||||
}
|
||||
|
||||
static void StartSyncCache()
|
||||
{
|
||||
if (sCheckTimer != HTIMER_INVALID) {
|
||||
HTimerRemove(sCheckTimer);
|
||||
sCheckTimer = HTIMER_INVALID;
|
||||
}
|
||||
|
||||
sCheckTimer = HTimerAdd(HFLASH_TIMER_ID, 0, CheckSyncCache, kHTimerLoop);
|
||||
}
|
||||
|
||||
static void ScheduleHeat()
|
||||
{
|
||||
if (HDLogGetTime() - sInfo.currHeatTime < HEAT_TIME_MS) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint16_t i = 0; i < sInfo.useNum; ++i) {
|
||||
if (sOpts->cache[i].eraseStatus || sOpts->cache[i].isDirty) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 仅对空闲页降温
|
||||
sOpts->cache[i].heat >>= 1;
|
||||
}
|
||||
|
||||
sInfo.currHeatTime = HDLogGetTime();
|
||||
}
|
||||
|
||||
static HFlashMemCache *FindMinHeatCache()
|
||||
{
|
||||
int16_t index = -1;
|
||||
uint8_t minHeat = MAX_HEAT;
|
||||
for (uint16_t i = 0; i < sInfo.useNum; ++i) {
|
||||
if (sOpts->cache[i].eraseStatus || sOpts->cache[i].isDirty) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 寻找最小热度
|
||||
const uint8_t currHeat = sOpts->cache[i].heat;
|
||||
if (index == -1) {
|
||||
index = i;
|
||||
minHeat = currHeat;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (currHeat > minHeat) {
|
||||
continue;
|
||||
}
|
||||
|
||||
index = i;
|
||||
minHeat = currHeat;
|
||||
}
|
||||
|
||||
if (index == -1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return sOpts->cache + index;
|
||||
}
|
||||
|
||||
static HFlashMemCache *FindReadCache(uint32_t addr, uint8_t needRead)
|
||||
static HFlashMemCache *FindReadCache(uint32_t addr, uint8_t needRead, uint8_t allowBypass)
|
||||
{
|
||||
addr = Align4K(addr);
|
||||
if (addr + HFLASH_BLOCK_SIZE > sOpts->flashSize) {
|
||||
@ -290,54 +398,56 @@ static HFlashMemCache *FindReadCache(uint32_t addr, uint8_t needRead)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (uint16_t i = 0; i < sInfo.useNum; ++i) {
|
||||
if (addr != sOpts->cache[i].addr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
sOpts->cache[i].heat = FAST_MIN(uint8_t, sOpts->cache[i].heat + 1, MAX_HEAT);
|
||||
return sOpts->cache + i;
|
||||
HFlashMemCache *cache = FindCacheByAddr(addr);
|
||||
if (cache) {
|
||||
ClearBypassAddr(addr);
|
||||
TouchCache(cache);
|
||||
return cache;
|
||||
}
|
||||
|
||||
// 如果缓存没有满, 直接增加
|
||||
if (sInfo.useNum < sOpts->cacheSize) {
|
||||
const uint16_t index = sInfo.useNum;
|
||||
++sInfo.useNum;
|
||||
cache = sOpts->cache + index;
|
||||
InitCache(cache, index, addr, 1);
|
||||
if (needRead) {
|
||||
WatiErase();
|
||||
if (sOpts->read(addr, GetMMap(index), HFLASH_BLOCK_SIZE) == 0) {
|
||||
LogE("addr[0x%08x], read faild", addr);
|
||||
if (LoadCachePage(cache, addr) == 0) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
memset(sOpts->cache + index, 0, sizeof(HFlashMemCache));
|
||||
sOpts->cache[index].addr = addr;
|
||||
sOpts->cache[index].offset = index;
|
||||
sOpts->cache[index].heat = FAST_MIN(uint8_t, sOpts->cache[index].heat + 1, MAX_HEAT);
|
||||
return sOpts->cache + index;
|
||||
ClearBypassAddr(addr);
|
||||
++sInfo.useNum;
|
||||
return cache;
|
||||
}
|
||||
|
||||
// 查找空闲的最低热度页
|
||||
HFlashMemCache *cache = FindMinHeatCache();
|
||||
if (cache == NULL || cache->heat > READ_MIN_HEAT) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const uint16_t index = cache->offset;
|
||||
memset(cache, 0, sizeof(HFlashMemCache));
|
||||
cache->addr = addr;
|
||||
cache->offset = index;
|
||||
cache->heat = READ_MIN_HEAT;
|
||||
|
||||
if (needRead) {
|
||||
WatiErase();
|
||||
if (sOpts->read(addr, GetMMap(index), HFLASH_BLOCK_SIZE) == 0) {
|
||||
LogE("addr[0x%08x], read faild", addr);
|
||||
cache = FindCleanVictim();
|
||||
if (cache == NULL && allowBypass && needRead) {
|
||||
// bypass 只允许真正的读 miss
|
||||
// 普通读接口可以接受本次直接读 flash, 但像 mmap/callback 这种需要稳定页指针的场景必须强制拿到 cache
|
||||
RecordBypassAddr(addr);
|
||||
if (sInfo.bypassCount < BYPASS_PROMOTE_THRESHOLD) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (cache == NULL) {
|
||||
cache = ReclaimOneCleanCache();
|
||||
}
|
||||
if (cache == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const uint16_t index = cache->offset;
|
||||
InitCache(cache, index, addr, 1);
|
||||
|
||||
if (needRead) {
|
||||
if (LoadCachePage(cache, addr) == 0) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
ClearBypassAddr(addr);
|
||||
return cache;
|
||||
}
|
||||
|
||||
@ -349,38 +459,47 @@ static HFlashMemCache *FindWriteCache(uint32_t addr, uint8_t needRead)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
HFlashMemCache *cache = FindReadCache(addr, needRead);
|
||||
HFlashMemCache *cache = FindCacheByAddr(addr);
|
||||
if (cache) {
|
||||
ClearBypassAddr(addr);
|
||||
TouchCache(cache);
|
||||
return cache;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
// 写入模式下, 需要抢占缓存页
|
||||
cache = FindMinHeatCache();
|
||||
if (cache == NULL) {
|
||||
// 如果在创建模式下, 没有一个空闲的缓存, 就需要先同步脏页, 再获取一个
|
||||
FastSyncCache();
|
||||
continue;
|
||||
}
|
||||
|
||||
const uint16_t index = cache->offset;
|
||||
memset(cache, 0, sizeof(HFlashMemCache));
|
||||
cache->addr = addr;
|
||||
cache->offset = index;
|
||||
cache->heat = READ_MIN_HEAT;
|
||||
if (sInfo.useNum < sOpts->cacheSize) {
|
||||
const uint16_t index = sInfo.useNum;
|
||||
cache = sOpts->cache + index;
|
||||
InitCache(cache, index, addr, 0);
|
||||
if (needRead) {
|
||||
WatiErase();
|
||||
// 找到一个空闲且最低温度的
|
||||
if (sOpts->read(addr, GetMMap(index), HFLASH_BLOCK_SIZE) == 0) {
|
||||
LogE("addr[0x%08x], read faild", addr);
|
||||
if (LoadCachePage(cache, addr) == 0) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
ClearBypassAddr(addr);
|
||||
++sInfo.useNum;
|
||||
return cache;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
cache = FindCleanVictim();
|
||||
if (cache == NULL) {
|
||||
cache = ReclaimOneCleanCache();
|
||||
}
|
||||
if (cache == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
{
|
||||
const uint16_t index = cache->offset;
|
||||
InitCache(cache, index, addr, 0);
|
||||
if (needRead) {
|
||||
if (LoadCachePage(cache, addr) == 0) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
ClearBypassAddr(addr);
|
||||
}
|
||||
|
||||
return cache;
|
||||
}
|
||||
|
||||
|
||||
@ -393,9 +512,6 @@ static uint8_t WriteData(uint32_t addr, const void *buf, uint32_t len, void (*cp
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 开启逐步同步
|
||||
StartSyncCache();
|
||||
|
||||
// 找到映射表, 先处理首页
|
||||
const uint8_t *bufPtr = (const uint8_t *)buf;
|
||||
const uint32_t offset = addr - cache->addr;
|
||||
@ -430,6 +546,8 @@ static uint8_t WriteData(uint32_t addr, const void *buf, uint32_t len, void (*cp
|
||||
cpCall(GetMMap(cache->offset), bufPtr, len, userData);
|
||||
}
|
||||
|
||||
// 写路径只负责标脏, 后台异步回收逐步推进, 避免小缓存下同步冲刷
|
||||
StartSyncCache();
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -461,7 +579,7 @@ static uint8_t FindReadPageCopy(uint32_t addr, void *buf, uint32_t len)
|
||||
return 0;
|
||||
}
|
||||
|
||||
HFlashMemCache *cache = FindReadCache(pageAddr, 1);
|
||||
HFlashMemCache *cache = FindReadCache(pageAddr, 1, 1);
|
||||
if (cache) {
|
||||
memcpy(p, GetMMap(cache->offset) + offset, copyLen);
|
||||
} else {
|
||||
@ -501,6 +619,14 @@ void HFlashMemInit(HFlashMemOpts *opts)
|
||||
FATAL_ERROR("flash Size not 4k align");
|
||||
return ;
|
||||
}
|
||||
|
||||
// 重新初始化时会把运行态和定时器一并清掉
|
||||
// 这些状态记录的是上一次 cache 使用轨迹和异步擦除进度, 沿用会把新配置带进旧状态机
|
||||
memset(&sInfo, 0, sizeof(sInfo));
|
||||
if (sCheckTimer != HTIMER_INVALID) {
|
||||
HTimerRemove(sCheckTimer);
|
||||
sCheckTimer = HTIMER_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
const HFlashMemOpts *HFlashMemGetOpt()
|
||||
@ -518,7 +644,6 @@ uint8_t HFlashMemRead(uint32_t addr, void *buf, uint32_t len)
|
||||
return 1;
|
||||
}
|
||||
|
||||
ScheduleHeat();
|
||||
uint8_t *p = (uint8_t *)buf;
|
||||
while (len > 0) {
|
||||
const uint32_t pageAddr = Align4K(addr);
|
||||
@ -530,7 +655,7 @@ uint8_t HFlashMemRead(uint32_t addr, void *buf, uint32_t len)
|
||||
return 0;
|
||||
}
|
||||
|
||||
HFlashMemCache *cache = FindReadCache(pageAddr, 1);
|
||||
HFlashMemCache *cache = FindReadCache(pageAddr, 1, 1);
|
||||
if (cache) {
|
||||
memcpy(p, GetMMap(cache->offset) + offset, copyLen);
|
||||
} else {
|
||||
@ -565,7 +690,6 @@ uint8_t HFlashMemWrite(uint32_t addr, const void *buf, uint32_t len)
|
||||
return 1;
|
||||
}
|
||||
|
||||
ScheduleHeat();
|
||||
return WriteData(addr, buf, len, _MemCpyHelper, NULL);
|
||||
}
|
||||
|
||||
@ -581,7 +705,6 @@ uint8_t HFlashMemSetValue(uint32_t addr, uint8_t value, uint32_t len)
|
||||
return 0;
|
||||
}
|
||||
|
||||
ScheduleHeat();
|
||||
return WriteData(addr, NULL, len, _MemSetValueHelper, &value);
|
||||
}
|
||||
|
||||
@ -597,7 +720,6 @@ uint8_t HFlashMemAddrCopy(uint32_t srcAddr, uint32_t destAddr, uint32_t len)
|
||||
return 0;
|
||||
}
|
||||
|
||||
ScheduleHeat();
|
||||
return WriteData(destAddr, NULL, len, _MemAddrCopy, &srcAddr);
|
||||
}
|
||||
|
||||
@ -607,15 +729,15 @@ uint8_t HFlashMemMMapCall(uint32_t addr, uint8_t(*call)(uint32_t addr, uint32_t
|
||||
return 0;
|
||||
}
|
||||
|
||||
ScheduleHeat();
|
||||
uint32_t offset = 0;
|
||||
HFlashMemCache *cache = NULL;
|
||||
uint16_t len = 0;
|
||||
uint8_t result = 0;
|
||||
|
||||
// 先处理未对齐的部分
|
||||
if (addr != Align4K(addr)) {
|
||||
cache = FindWriteCache(addr + offset, 1);
|
||||
// 这里显式禁止 bypass
|
||||
// 回调拿到的是 cache 内存指针, 如果退化成直读 flash, 本接口就无法提供连续且可复用的页视图
|
||||
HFlashMemCache *cache = FindReadCache(addr + offset, 1, 0);
|
||||
if (cache == NULL) {
|
||||
LogE("addr[0x%08x], find cache faild", addr);
|
||||
return 0;
|
||||
@ -632,7 +754,7 @@ uint8_t HFlashMemMMapCall(uint32_t addr, uint8_t(*call)(uint32_t addr, uint32_t
|
||||
|
||||
// 剩余处理对齐部分
|
||||
while (result == 0) {
|
||||
cache = FindWriteCache(addr + offset, 1);
|
||||
HFlashMemCache *cache = FindReadCache(addr + offset, 1, 0);
|
||||
if (cache == NULL) {
|
||||
LogE("addr[0x%08x], find cache faild", addr + offset);
|
||||
return 0;
|
||||
@ -651,14 +773,19 @@ uint8_t HFlashMemMMapCall(uint32_t addr, uint8_t(*call)(uint32_t addr, uint32_t
|
||||
|
||||
void HFlashMemSync()
|
||||
{
|
||||
ScheduleHeat();
|
||||
if (sCheckTimer != HTIMER_INVALID) {
|
||||
HTimerRemove(sCheckTimer);
|
||||
sCheckTimer = HTIMER_INVALID;
|
||||
}
|
||||
SyncCache();
|
||||
}
|
||||
|
||||
void HFlashMemFreeCache()
|
||||
{
|
||||
HFlashMemSync();
|
||||
sInfo.useNum = 0;
|
||||
sInfo.currHeatTime = HDLogGetTime();
|
||||
if (sCheckTimer != HTIMER_INVALID) {
|
||||
HTimerRemove(sCheckTimer);
|
||||
sCheckTimer = HTIMER_INVALID;
|
||||
}
|
||||
memset(&sInfo, 0, sizeof(sInfo));
|
||||
}
|
||||
|
||||
|
||||
@ -4,7 +4,9 @@
|
||||
#include "HDLog.h"
|
||||
#include "HVector.h"
|
||||
#include "HTimer.h"
|
||||
#if HFLASH_USE_HSHELL
|
||||
#include "HShellLex.h"
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef HFLASH_USE_FLASH_MEM
|
||||
@ -49,7 +51,9 @@ __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
|
||||
@ -60,7 +64,9 @@ void HDMainLoopCallOverride(uint8_t event)
|
||||
// 检查是不是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))
|
||||
|
||||
#if HFLASH_USE_HSHELL
|
||||
enum eShell
|
||||
{
|
||||
kShellPageInfo, ///< 查看页表信息
|
||||
@ -84,6 +90,7 @@ static HShellMatch sShellMatch[] = {
|
||||
HSHELL_MATCH_ITEM(kShellFlashMemInfo, "flashMemInfo"),
|
||||
#endif
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
union PageInfo {
|
||||
@ -104,9 +111,9 @@ struct Info {
|
||||
HFlashAddr_t pageAddr; ///< 页表地址
|
||||
HFlashAddr_t pageBackupAddr; ///< 页表备份地址
|
||||
uint32_t pageSize; ///< 页大小
|
||||
HFlashAddr_t protectAddr; ///< 保护区地址
|
||||
HFlashAddr_t protectBackupAddr; ///< 保护区备份地址
|
||||
uint32_t protectSize; ///< 保护区大小
|
||||
HFlashProtectInfo *protectInfo; ///< 保护区描述缓存
|
||||
uint16_t protectCacheSize; ///< 保护区描述缓存大小
|
||||
uint16_t protectUseNum; ///< 保护区使用数量
|
||||
HFlashCacheInfo *pageCache; ///< 页表缓存
|
||||
uint16_t pageCacheSize; ///< 页表缓存大小
|
||||
uint16_t pageCacheUseNum; ///< 页表缓存使用页
|
||||
@ -130,30 +137,193 @@ static HTimer_t sSyncCacheTimer = HTIMER_INVALID;
|
||||
static HVECTOR_DEFINE32(sNeedBackupOffset, 10);
|
||||
|
||||
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 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;
|
||||
}
|
||||
|
||||
HVectorClear(sNeedBackupOffset);
|
||||
}
|
||||
|
||||
///< 检查地址是否在双备份保护区内
|
||||
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;
|
||||
}
|
||||
|
||||
if (addr < sInfo.protectAddr || addr >= sInfo.protectAddr + sInfo.protectSize) {
|
||||
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;
|
||||
}
|
||||
|
||||
if (addrEnd > sInfo.protectAddr + sInfo.protectSize) {
|
||||
FATAL_ERROR("addr[0x%08x][0x%08x] size[%d][%d] overflow protect", addr, sInfo.protectAddr, size, sInfo.protectSize);
|
||||
HFlashAddr_t backupAddr = 0;
|
||||
if (GetBackupAddr(addr, size, &backupAddr) == 0) {
|
||||
LogE("backup addr[0x%08x] not config", addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
return ReadFlashCall(backupAddr, data, size);
|
||||
}
|
||||
|
||||
static uint8_t ReadFlashCall(HFlashAddr_t addr, void *data, uint32_t size)
|
||||
@ -330,6 +500,19 @@ 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 SyncBackup()
|
||||
{
|
||||
LogD("Start sync Backup");
|
||||
@ -340,8 +523,7 @@ static void SyncBackup()
|
||||
|
||||
for (uint16_t i = 0; i < HVectorGetUseLen(sNeedBackupOffset); ++i) {
|
||||
const uint32_t addr = HVectorGetData(sNeedBackupOffset, i);
|
||||
const uint32_t destAddr = sInfo.protectBackupAddr + (addr - sInfo.protectAddr);
|
||||
if (RestoreBackup(addr, destAddr, HFLASH_BLOCK_SIZE) == 0) {
|
||||
if (SyncBackupRange(addr, HFLASH_BLOCK_SIZE) == 0) {
|
||||
LogE("RestorePage faild, addr[0x%08x]", addr);
|
||||
StartSyncBackupTimer();
|
||||
return ;
|
||||
@ -351,9 +533,9 @@ static void SyncBackup()
|
||||
HVectorClear(sNeedBackupOffset);
|
||||
|
||||
// 备份页表数据
|
||||
const uint32_t crcValue = GetFlashCrc32(AdjustPageAddr(sInfo.pageBackupAddr), AdjustPageByte(sPageInfo.useNum));
|
||||
const uint32_t crcValue = GetBackupCrc32(AdjustPageAddr(sInfo.pageAddr), AdjustPageByte(sPageInfo.useNum));
|
||||
if (crcValue != sPageInfo.crc32) {
|
||||
RestoreBackup(sInfo.pageAddr, sInfo.pageBackupAddr, AdjustPageByte(sPageInfo.useNum + 1));
|
||||
SyncBackupRange(sInfo.pageAddr, AdjustPageByte(sPageInfo.useNum + 1));
|
||||
}
|
||||
LogD("Sync Backup End");
|
||||
}
|
||||
@ -466,6 +648,21 @@ static uint32_t GetFlashCrc32(HFlashAddr_t addr, uint32_t size)
|
||||
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) {
|
||||
@ -541,6 +738,31 @@ _FlashError:
|
||||
#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)
|
||||
{
|
||||
@ -549,9 +771,7 @@ static uint8_t RestorePage(uint32_t index)
|
||||
return 0;
|
||||
}
|
||||
|
||||
const HFlashAddr_t srcAddr = AdjustPageAddrOffset(sInfo.pageBackupAddr, index);
|
||||
const HFlashAddr_t dstAddr = AdjustPageAddrOffset(sInfo.pageAddr, index);
|
||||
return RestoreBackup(srcAddr, dstAddr, sizeof(HFlashPageInfo));
|
||||
return RestoreBackupRange(AdjustPageAddrOffset(sInfo.pageAddr, index), sizeof(HFlashPageInfo));
|
||||
}
|
||||
|
||||
static void SyncPageInfo()
|
||||
@ -944,6 +1164,18 @@ void HFlashSetPageCache(HFlashCacheInfo *pageInfo, uint16_t size)
|
||||
sInfo.pageCacheSize = size;
|
||||
}
|
||||
|
||||
void HFlashSetProtectCache(HFlashProtectInfo *protectInfo, uint16_t size)
|
||||
{
|
||||
ResetRuntimeState();
|
||||
sInfo.protectInfo = protectInfo;
|
||||
sInfo.protectCacheSize = size;
|
||||
sInfo.protectUseNum = 0;
|
||||
|
||||
if (protectInfo != NULL && size) {
|
||||
memset(protectInfo, 0, size * sizeof(HFlashProtectInfo));
|
||||
}
|
||||
}
|
||||
|
||||
void HFlashSetPageAddr(HFlashAddr_t addr, uint32_t size)
|
||||
{
|
||||
if (IS_NOT_4K(addr) || IS_NOT_4K(size)) {
|
||||
@ -956,42 +1188,200 @@ void HFlashSetPageAddr(HFlashAddr_t addr, uint32_t size)
|
||||
|
||||
void HFlashSetPageBackupAddr(HFlashAddr_t addr, uint32_t size)
|
||||
{
|
||||
if (IS_NOT_4K(addr) || IS_NOT_4K(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 (sInfo.pageSize != size) {
|
||||
FATAL_ERROR("page size not match[%d][%d]", sInfo.pageSize, size);
|
||||
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;
|
||||
sInfo.pageSize = size;
|
||||
}
|
||||
|
||||
void HFlashSetProtectAddr(HFlashAddr_t addr, uint32_t size)
|
||||
static uint8_t CheckProtectConflict(HFlashAddr_t addr, uint32_t size, HFlashAddr_t backupAddr)
|
||||
{
|
||||
if (IS_NOT_4K(addr) || IS_NOT_4K(size)) {
|
||||
FATAL_ERROR("not align page size[0x%08x], size[%x]", addr, size);
|
||||
HFlashAddr_t adjustAddr = 0;
|
||||
uint32_t backupSize = 0;
|
||||
if (GetProtectBackupRange(addr, size, &adjustAddr, &backupSize) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
sInfo.protectAddr = addr;
|
||||
sInfo.protectSize = size;
|
||||
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 HFlashSetProtectBackupAddr(HFlashAddr_t addr, uint32_t size)
|
||||
void HFlashClearProtectAddr()
|
||||
{
|
||||
if (IS_NOT_4K(addr) || IS_NOT_4K(size)) {
|
||||
FATAL_ERROR("not align page size[0x%08x], size[%x]", addr, size);
|
||||
ResetRuntimeState();
|
||||
sInfo.protectUseNum = 0;
|
||||
if (sInfo.protectInfo != NULL && sInfo.protectCacheSize) {
|
||||
memset(sInfo.protectInfo, 0, sInfo.protectCacheSize * sizeof(HFlashProtectInfo));
|
||||
}
|
||||
}
|
||||
|
||||
if (sInfo.protectSize != size) {
|
||||
FATAL_ERROR("protect size not match[%d][%d]", sInfo.protectSize, size);
|
||||
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 ;
|
||||
}
|
||||
|
||||
sInfo.protectBackupAddr = addr;
|
||||
sInfo.protectSize = size;
|
||||
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];
|
||||
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) {
|
||||
sInfo.protectInfo[i] = sInfo.protectInfo[i + 1];
|
||||
}
|
||||
|
||||
--sInfo.protectUseNum;
|
||||
memset(&sInfo.protectInfo[sInfo.protectUseNum], 0, sizeof(HFlashProtectInfo));
|
||||
}
|
||||
|
||||
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)
|
||||
@ -1010,6 +1400,7 @@ static uint8_t _Print(uint32_t index, HFlashPageInfo *info, void *userData)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if HFLASH_USE_HSHELL
|
||||
static void Shell(HSHELL_FUNC_ARGS)
|
||||
{
|
||||
uint32_t arg1 = 0;
|
||||
@ -1048,7 +1439,7 @@ static void Shell(HSHELL_FUNC_ARGS)
|
||||
HFlashResetPage();
|
||||
} break;
|
||||
case kShellRestorePage: {
|
||||
RestoreBackup(sInfo.pageAddr, sInfo.pageBackupAddr, AdjustPageByte(sPageInfo.pageNum + 1));
|
||||
RestoreBackupRange(sInfo.pageAddr, AdjustPageByte(sPageInfo.pageNum + 1));
|
||||
} break;
|
||||
#ifdef HFLASH_USE_FLASH_MEM
|
||||
case kShellFlashMemInfo: {
|
||||
@ -1058,7 +1449,13 @@ static void Shell(HSHELL_FUNC_ARGS)
|
||||
}
|
||||
|
||||
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);
|
||||
HSHELL_PRINTFL("addr[0x%08x], offset[%d], eraseStatus[%d], isDirty[%d], referenced[%d], probation[%d]",
|
||||
opt->cache[i].addr,
|
||||
opt->cache[i].offset,
|
||||
opt->cache[i].eraseStatus,
|
||||
opt->cache[i].isDirty,
|
||||
opt->cache[i].referenced,
|
||||
opt->cache[i].probation);
|
||||
}
|
||||
} break;
|
||||
#endif
|
||||
@ -1066,18 +1463,20 @@ static void Shell(HSHELL_FUNC_ARGS)
|
||||
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 (IsOverLap(sInfo.pageAddr, sInfo.pageSize, sInfo.pageBackupAddr, sInfo.pageSize)) {
|
||||
FATAL_ERROR("page table and backup table is overlap");
|
||||
if (CheckBackupArea() == 0) {
|
||||
LogE("Backup area check faild");
|
||||
return ;
|
||||
}
|
||||
|
||||
@ -1101,15 +1500,15 @@ void HFlashInitCheck()
|
||||
|
||||
LogD("page table is invalid, check backup table");
|
||||
// 备份校验
|
||||
if (ReadFlashCall(sInfo.pageBackupAddr, sPageInfo.reverse, sizeof(sPageInfo)) == 0) {
|
||||
LogE("Read backup page table[0x%08x] faild", sInfo.pageBackupAddr);
|
||||
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 || GetFlashCrc32(AdjustPageAddr(sInfo.pageBackupAddr), AdjustPageByte(sPageInfo.useNum)) != sPageInfo.crc32;
|
||||
invalid = invalid || GetBackupCrc32(AdjustPageAddr(sInfo.pageAddr), AdjustPageByte(sPageInfo.useNum)) != sPageInfo.crc32;
|
||||
if (invalid) {
|
||||
// 备份也无效, 首次创建, 去初始化数据
|
||||
LogD("backup page table is invalid, init data");
|
||||
@ -1117,7 +1516,7 @@ void HFlashInitCheck()
|
||||
}
|
||||
|
||||
// 备份校验通过, 恢复全备份数据
|
||||
RestoreBackup(sInfo.pageBackupAddr, sInfo.pageAddr, sInfo.pageSize);
|
||||
RestoreBackupRange(sInfo.pageAddr, sInfo.pageSize);
|
||||
return ;
|
||||
} while (0);
|
||||
|
||||
@ -1191,7 +1590,7 @@ void HFlashRegister(HFlashAddr_t addr, uint32_t size)
|
||||
|
||||
// 先恢复内容区域
|
||||
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);
|
||||
RestoreBackupRange(cache->info.addr, cache->info.size);
|
||||
|
||||
// 如果恢复后还校验失败, 那就恢复对应页表
|
||||
const uint32_t contentCrc = GetFlashCrc32(cache->info.addr, cache->info.useSize);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user