/*
 * PFM_MemotyCheck.c
 *
 *  Created on: 2021年9月29日
 *      Author: fengr
 */



#include "PFM_MemoryCheck.h"
#include "CM_Memory.h"
#include "CM_MultiThread.h"
#include "CM_Mutex.h"
#include "CM_Time.h"
#include "DFM_Time.h"
#include "CM_MD5.h"
#include "PFM_Cfg.h"
#include "CM_CRC32.h"
#include "PFM_Log.h"
/* 内存自检结构体 */
typedef struct
{
	CM_UINT64 memCheckAddr;/*- 存储内存数据地址*/
	CM_UINT32  memCheckLen;/*- 存储内存数据长度*/
    MD5Context_T md5Str;/*- 周期分片校验的MD5结构体*/
    CM_UINT8   md5[16];/*- 存储初始比较时的校验码*/
    CM_UINT32  blocklen;/*- 分块校验数据长度*/
    CM_UINT32  blockcnt;/*- 分块数*/
    CM_UINT32  offset;/*- 当前待校验块索引*/
}STRU_MEM_CHECKT;

/* 内存自检控制结构体 */
typedef struct
{
	STRU_MEM_CHECKT memCheckCtrl[1024];/*- 内存自检控制*/
	CM_UINT16 memCheckNum;/*- 内存自检控制总数量*/
	CM_UINT16 memi;/*- 内存自检控制当前位*/
	CM_UINT8  memInitFlag;/*- 内存自检是否处于初始化阶段标志位*/
}STRU_MEM_CHECK_CTRL_T;

static STRU_MEM_CHECK_CTRL_T s_MemCheckCtrl;

/*定义分块自检长度*/
#define MEM_BLOCK_LEN (32u)


void static s_MemSegRWTest(CM_UINT8 *pBottom, CM_UINT8 *pTop);
static ENUM_CM_RETURN s_Abraham_inc(IN CM_UINT8* pStart, IN CM_UINT8* pEnd, CM_UINT8 flagPre, CM_UINT8 flagNew);
static ENUM_CM_RETURN s_Abraham_dec(IN CM_UINT8* pStart, IN CM_UINT8* pEnd, CM_UINT8 flagPre, CM_UINT8 flagNew);
static ENUM_CM_RETURN s_Abraham_inc2(IN CM_UINT8* pStart, IN CM_UINT8* pEnd, CM_UINT8 flagPre, CM_UINT8 flagNew);
static ENUM_CM_RETURN s_Abraham_dec2(IN CM_UINT8* pStart, IN CM_UINT8* pEnd, CM_UINT8 flagPre, CM_UINT8 flagNew);
static void PFM_Mem_BlockCheck(STRU_MEM_CHECKT *pManage);
/**
* @brief 内存自检初始化
* @details 注册平台需自检的关键变量
*/
void PFM_MemCheck_Init(void)
{
	ENUM_CM_RETURN ret = ENUM_CM_FALSE;
	ret = CM_Memset(&s_MemCheckCtrl, 0u, sizeof(s_MemCheckCtrl),  sizeof(s_MemCheckCtrl));
	CM_NM_ASSERT(ENUM_CM_TRUE == ret, MEMORY_CHECK_MODE, DARK_FAULT_CODE_FUN_ORDER_1, TSCP_DARK_ASSERT_1);
	s_MemCheckCtrl.memi = 0u;
	s_MemCheckCtrl.memInitFlag = 0u;
	PFM_MemCheck_Register((CM_UINT8 *)&g_PFM_Cfg, (CM_UINT32)sizeof(g_PFM_Cfg));
}

/**
* @brief 变量内存自检注册初始化
* @param pMemAddr注册变量的首地址
* 		 dataLen 注册变量的大小
*/
void PFM_MemCheck_Register(CM_UINT8* pMemAddr,CM_UINT32 dataLen)
{
	/*- 入参是否非空*/
	if(NULL != pMemAddr)
	{
		/*- 记录需要校验的地址*/ /*TODO 需要验证在QNX下地址是否为32字节，可能会存在问题*/
		s_MemCheckCtrl.memCheckCtrl[s_MemCheckCtrl.memCheckNum].memCheckAddr = (CM_UINT64)pMemAddr;
		/*- 记录需要校验数据的长度*/
		s_MemCheckCtrl.memCheckCtrl[s_MemCheckCtrl.memCheckNum].memCheckLen = dataLen;
		/*- 设置分块大小*/
		s_MemCheckCtrl.memCheckCtrl[s_MemCheckCtrl.memCheckNum].blocklen = MEM_BLOCK_LEN;
		/*- 计算分块数量*/
		s_MemCheckCtrl.memCheckCtrl[s_MemCheckCtrl.memCheckNum].blockcnt \
		= (dataLen + MEM_BLOCK_LEN - 1u)/MEM_BLOCK_LEN;
		/*- 文件偏移量初始化*/
		s_MemCheckCtrl.memCheckCtrl[s_MemCheckCtrl.memCheckNum].offset = 0u;

		/* printf("0x%p  \r\n",pMemAddr); */
		/* printf("0x%p  \r\n",s_MemCheckCtrl.memCheckCtrl[s_MemCheckCtrl.memCheckNum].memCheckAddr); */
		/*- 记录器加一*/
		s_MemCheckCtrl.memCheckNum++;

	}
	else
	{
		/*- 宕机处理*/
		CM_NM_ASSERT(0, MEMORY_CHECK_MODE, DARK_FAULT_CODE_FUN_ORDER_2, TSCP_DARK_ASSERT_1);
	}
}


/**
* @brief 分块计算MD5自检接口
* @param pManage 自检管理结构体
* @details
*/
static void PFM_Mem_BlockCheck(STRU_MEM_CHECKT *pManage)
{
	/*- 变量初始化 */
	CM_UINT8 tmpBuf[MEM_BLOCK_LEN * 2u] = {0u};
	CM_UINT8 *pStaddr = NULL;
	CM_UINT8 *pEndaddr = NULL;
	CM_UINT32 destcrc = 0u;
	CM_UINT32 srcCrc = 0u;
	/*- 入参指针是否非空 */
	if(NULL != pManage)
	{
		/*- 分块计算，是否计算到了最后一块 */
        if(((pManage->offset + 1u) * pManage->blocklen) <= pManage->memCheckLen)
        {
        	/*- 自检起始地址 */
        	pStaddr = (CM_UINT8 *)(pManage->memCheckAddr + (pManage->offset * pManage->blocklen)) ;

        	/*- 自检结束地址 */
        	pEndaddr = (CM_UINT8 *)(pManage->memCheckAddr + (pManage->offset * pManage->blocklen) + pManage->blocklen - 1u) ;

        	/*- 计算拷贝前的数据crc */
        	srcCrc = CM_Crc32(pStaddr,pManage->blocklen);

        	/*- 在检测前先拷贝数据到缓冲区 */
        	(void)CM_Memcpy(tmpBuf, (CM_SIZE_T)(MEM_BLOCK_LEN * 2u), pStaddr, (CM_SIZE_T)pManage->blocklen);

        	/*- 计算拷贝后的缓存区数据crc */
        	destcrc = CM_Crc32(tmpBuf,pManage->blocklen);
        	/*- 检测拷贝前后crc是否相同 */
        	CM_NM_ASSERT(destcrc == srcCrc,MEMORY_CHECK_MODE, DARK_FAULT_CODE_FUN_ORDER_3, TSCP_DARK_ASSERT_1);
        	/*- 内存自检 */
        	s_MemSegRWTest(pStaddr , pEndaddr);

        	/*- 检测后恢复缓冲区数据 */
        	(void)CM_Memcpy(pStaddr, (CM_SIZE_T)pManage->blocklen, tmpBuf, (CM_SIZE_T)pManage->blocklen);

        	/*- 恢复后计算crc */
        	srcCrc = CM_Crc32(pStaddr,pManage->blocklen);

        	/*- 检测恢复后，crc是否一致 */
        	CM_NM_ASSERT(destcrc == srcCrc, MEMORY_CHECK_MODE, DARK_FAULT_CODE_FUN_ORDER_3, TSCP_DARK_ASSERT_2);

        	pManage->offset++;
        }
        else
        {
        	/*- 自检起始地址 */
        	pStaddr = (CM_UINT8 *)(pManage->memCheckAddr + (pManage->offset * pManage->blocklen));

        	/*- 自检结束地址,地址 -1 为32个数据 */
        	pEndaddr = (CM_UINT8 *)(pManage->memCheckAddr + (pManage->offset * pManage->blocklen) + (pManage->memCheckLen - (pManage->blocklen * pManage->offset) - 1u));

        	/*- 计算拷贝前的数据crc */
        	if(pManage->memCheckLen > (pManage->blocklen * pManage->offset))
        	{
            	srcCrc = CM_Crc32(pStaddr,(pManage->memCheckLen - (pManage->blocklen * pManage->offset)));
        	}
        	else
        	{
        		MSCP_LOG_MSG("crc32 enter len is err = %d\n",pManage->memCheckLen - (pManage->blocklen * pManage->offset));
        	}

        	/*- 在检测前先拷贝数据到缓冲区 */
        	(void)CM_Memcpy(tmpBuf, MEM_BLOCK_LEN * 2u, pStaddr, (pManage->memCheckLen - (pManage->blocklen * pManage->offset)));

        	if(pManage->memCheckLen > (pManage->blocklen * pManage->offset))
        	{
            	/*- 计算拷贝后的缓存区数据crc */
            	destcrc = CM_Crc32(tmpBuf,(pManage->memCheckLen - (pManage->blocklen * pManage->offset)));
        	}
        	else
        	{
        		MSCP_LOG_MSG("crc32 enter len is err = %d\n",pManage->memCheckLen - (pManage->blocklen * pManage->offset));
        	}

        	/*- 检测拷贝前后crc是否相同 */
        	CM_NM_ASSERT(destcrc == srcCrc, MEMORY_CHECK_MODE, DARK_FAULT_CODE_FUN_ORDER_3, TSCP_DARK_ASSERT_3);
        	/*- 内存自检 */
        	s_MemSegRWTest(pStaddr, pEndaddr);

        	/*- 检测后恢复缓冲区数据 */
        	(void)CM_Memcpy(pStaddr, (pManage->memCheckLen - (pManage->blocklen * pManage->offset)), tmpBuf, (pManage->memCheckLen - (pManage->blocklen * pManage->offset)));

        	if(pManage->memCheckLen > (pManage->blocklen * pManage->offset))
        	{
            	/*- 恢复后计算crc */
            	srcCrc = CM_Crc32(pStaddr,(pManage->memCheckLen - (pManage->blocklen * pManage->offset)));
        	}
        	else
        	{
        		MSCP_LOG_MSG("crc32 enter len is err = %d\n",pManage->memCheckLen - (pManage->blocklen * pManage->offset));
        	}

        	/*- 检测恢复后，crc是否一致 */
        	CM_NM_ASSERT(destcrc == srcCrc, MEMORY_CHECK_MODE, DARK_FAULT_CODE_FUN_ORDER_3, TSCP_DARK_ASSERT_4);

        	pManage->offset++;
        }

        /*- 是否全部自检完成  */
        if(pManage->offset == pManage->blockcnt)
        {
            /*- 自检完成，当前待校验索引块归0  */
            pManage->offset = 0u;
            /*- 自检完成，检查下一块关键变量  */
            s_MemCheckCtrl.memi++;
        }
        else
        {
            /*- 未自检完成，返回成功 */
        }

    }
	else
	{
		/*- 无需处理  */
	}

}

/**
* @brief
* @param pManage 自检管理结构体
* @details
*/
void PFM_MemCheck(void)
{
	/*- 变量初始化 */
	CM_UINT16 i = 0u;
	CM_UINT16 j = 0u;
	/*- 如果内存自检处于初始化阶段 */
	if(0u == s_MemCheckCtrl.memInitFlag)
	{
		/*- 循环检查每一个注册进来的地址 */
		for(i = 0u; i < s_MemCheckCtrl.memCheckNum; i++)
		{
			for(j = 0u; j < s_MemCheckCtrl.memCheckCtrl[i].blockcnt; j++)
			{
				PFM_Mem_BlockCheck(&s_MemCheckCtrl.memCheckCtrl[i]);
			}
		}
		/*- 内存自检标志位置于周期阶段 */
		s_MemCheckCtrl.memInitFlag = 1u;
	}
	else
	{
		/*- 是否全部自检完成 */
		if(s_MemCheckCtrl.memi >= s_MemCheckCtrl.memCheckNum)
		{
			/*- 重置自检索引*/
			s_MemCheckCtrl.memi = 0u;
		}

		/*- 按自检顺序分块自检*/
		PFM_Mem_BlockCheck(&s_MemCheckCtrl.memCheckCtrl[s_MemCheckCtrl.memi]);
	}
}

/*
* @brief Abraham算法内存段自检
* @param pStart 起始地址（低地址）
* @param pEnd 终止地址（高地址）
* @details
* 注意内存地址必须是4字节对齐的
*/
void static s_MemSegRWTest(CM_UINT8 *pBottom, CM_UINT8 *pTop)
{
	ENUM_CM_RETURN rt = ENUM_CM_FALSE;

    CM_ASSERT(pBottom <= pTop, MEMORY_CHECK_MODE, DARK_FAULT_CODE_FUN_ORDER_4, TSCP_DARK_ASSERT_1);
    CM_ASSERT(NULL != pBottom, MEMORY_CHECK_MODE, DARK_FAULT_CODE_FUN_ORDER_4, TSCP_DARK_ASSERT_1);
    CM_ASSERT(NULL != pTop, MEMORY_CHECK_MODE, DARK_FAULT_CODE_FUN_ORDER_4, TSCP_DARK_ASSERT_1);
    /*- 内存段初始化为全0 */
    rt = CM_Memset((void*)pBottom, (CM_UINT8)0u, (CM_SIZE_T)((pTop - pBottom) + 1), (CM_SIZE_T)((pTop - pBottom) + 1)); /* parasoft-suppress MISRA2004-17_1 MISRA2004-17_2 "提高代码执行效率" */
    CM_ASSERT(ENUM_CM_TRUE == rt, MEMORY_CHECK_MODE, DARK_FAULT_CODE_FUN_ORDER_4, TSCP_DARK_ASSERT_2);
    /*- Abraham算法 步骤1 */
    rt = s_Abraham_inc(pBottom, pTop, 0x00u, 0xFFu);
    CM_ASSERT(ENUM_CM_TRUE == rt, MEMORY_CHECK_MODE, DARK_FAULT_CODE_FUN_ORDER_4, TSCP_DARK_ASSERT_2);
    /*- Abraham算法 步骤2 */
    rt = s_Abraham_inc(pBottom, pTop, 0xFFu, 0x00u);
    CM_ASSERT(ENUM_CM_TRUE == rt, MEMORY_CHECK_MODE, DARK_FAULT_CODE_FUN_ORDER_4, TSCP_DARK_ASSERT_2);
    /*- Abraham算法 步骤3 */
    rt = s_Abraham_dec(pTop, pBottom, 0x00u, 0xFFu);
    CM_ASSERT(ENUM_CM_TRUE == rt, MEMORY_CHECK_MODE, DARK_FAULT_CODE_FUN_ORDER_4, TSCP_DARK_ASSERT_2);
    /*- Abraham算法 步骤4 */
    rt = s_Abraham_dec(pTop, pBottom, 0xFFu, 0x00u);
    CM_ASSERT(ENUM_CM_TRUE == rt, MEMORY_CHECK_MODE, DARK_FAULT_CODE_FUN_ORDER_4, TSCP_DARK_ASSERT_2);
    /*- Abraham算法 步骤5 */
    rt = s_Abraham_inc2(pBottom, pTop, 0x00u, 0xFFu);
    CM_ASSERT(ENUM_CM_TRUE == rt, MEMORY_CHECK_MODE, DARK_FAULT_CODE_FUN_ORDER_4, TSCP_DARK_ASSERT_2);
    /*- Abraham算法 步骤6 */
    rt = s_Abraham_dec2(pTop, pBottom, 0x00u, 0xFFu);
    CM_ASSERT(ENUM_CM_TRUE == rt, MEMORY_CHECK_MODE, DARK_FAULT_CODE_FUN_ORDER_4, TSCP_DARK_ASSERT_2);
    /*- 内存段初始化为全1 */
    rt = CM_Memset((void*)pBottom, (CM_UINT8)0xffu, (CM_SIZE_T)((pTop - pBottom) + 1), (CM_SIZE_T)((pTop - pBottom) + 1)); /* parasoft-suppress MISRA2004-17_1 MISRA2004-17_2 "提高代码执行效率" */
    CM_ASSERT(ENUM_CM_TRUE == rt, MEMORY_CHECK_MODE, DARK_FAULT_CODE_FUN_ORDER_4, TSCP_DARK_ASSERT_2);
    /*- Abraham算法 步骤7 */
    rt = s_Abraham_inc2(pBottom, pTop, 0xFFu, 0x00u);
    CM_ASSERT(ENUM_CM_TRUE == rt, MEMORY_CHECK_MODE, DARK_FAULT_CODE_FUN_ORDER_4, TSCP_DARK_ASSERT_2);
    /*- Abraham算法 步骤8 */
    rt = s_Abraham_dec2(pTop, pBottom, 0xFFu, 0x00u);
    CM_ASSERT(ENUM_CM_TRUE == rt, MEMORY_CHECK_MODE, DARK_FAULT_CODE_FUN_ORDER_4, TSCP_DARK_ASSERT_2);
    /*- 内存段初始化为全0 */
    rt = CM_Memset((void*)pBottom, (CM_UINT8)0u, (CM_SIZE_T)((pTop - pBottom) + 1), (CM_SIZE_T)((pTop - pBottom) + 1)); /* parasoft-suppress MISRA2004-17_1 MISRA2004-17_2 "提高代码执行效率" */
    CM_ASSERT(ENUM_CM_TRUE == rt, MEMORY_CHECK_MODE, DARK_FAULT_CODE_FUN_ORDER_4, TSCP_DARK_ASSERT_2);
}

/*
* @brief Abraham算法步骤12
* @param pStart 起始地址（低地址）
* @param pEnd 终止地址（高地址）
* @return 检查结果
* - ENUM_CM_TRUE 成功
* - ENUM_CM_FALSE 失败
* @details
* 自底向上：检查内存单元是否与flagPre相等，然后将内存单元更新乘flagNew
* 自顶向下：检查内存单元是否与flagNew相等
*/
static ENUM_CM_RETURN s_Abraham_inc(IN CM_UINT8 *pStart, IN CM_UINT8 *pEnd, CM_UINT8 flagPre, CM_UINT8 flagNew)
{
    volatile CM_UINT8 * p = NULL;
    CM_UINT32 val = 0u;
    /*- 初始化为自检失败 */
    ENUM_CM_RETURN rt = ENUM_CM_FALSE;

    CM_ASSERT(pStart <= pEnd,MEMORY_CHECK_MODE, DARK_FAULT_CODE_FUN_ORDER_5, TSCP_DARK_ASSERT_1);
    CM_ASSERT((CM_UINT64)pStart > 0u, MEMORY_CHECK_MODE, DARK_FAULT_CODE_FUN_ORDER_5, TSCP_DARK_ASSERT_1);
    CM_ASSERT((CM_UINT64)pEnd < CM_UINT64_MAX, MEMORY_CHECK_MODE, DARK_FAULT_CODE_FUN_ORDER_5, TSCP_DARK_ASSERT_1);

    /*- 从低地址开始 | 遍历至高地址 | 检查下一内存单元 */
    for (p = pStart; p <= pEnd; ++p) /* parasoft-suppress MISRA2004-17_1 "提高代码执行效率" */
    {
        /*- 读取内存单元 */
        val = *p;
        /*- 内存数值是否与预期一致 */
        if (val == flagPre)
        {
            /*- 更新内存数值 */
            *p = flagNew;
        }
        else
        {
        	MSCP_LOG_MSG("val 0x%x  flagPre 0x%x \r\n",val,flagPre);

            /*- 退出循环 */
            break;
        }

    }
    /*- 自底向上的遍历是否成功 */
    if (p > pEnd)
    {
        /*- 从高地址开始 | 遍历至低地址 | 检查下一内存单元 */
        for (p = pEnd; p >= pStart; --p) /* parasoft-suppress MISRA2004-17_1 "提高代码执行效率" */
        {
            /*- 读取内存单元 */
            val = *p;
            /*- 内存数值是否与预期不一致 */
            if (val != flagNew)
            {
            	MSCP_LOG_MSG("val 0x%x  flagNew 0x%x \r\n",val,flagNew);
                /*- 退出循环 */
                break;
            }
            else
            {
            	/*- 无处理 */
            }
        }
        /*- 自顶向下的遍历是否成功 */
        if (p < pStart)
        {
            /*- 自检成功 */
            rt = ENUM_CM_TRUE;
        }
        else
        {
        	MSCP_LOG_MSG("error \r\n");
        	/*- 无处理 */
        }
    }
    else
    {
    	/*- 无处理 */
    }
    /*- 返回自检结果 */
    return rt;
}

/*
* @brief Abraham算法步骤34
* @param pStart 起始地址(高地址）
* @param pEnd 终止地址（低地址）
* @return 检查结果
* - ENUM_CM_TRUE 成功
* - ENUM_CM_FALSE 失败
* @details
* 自底向上：检查内存单元是否与flagPre相等，然后将内存单元更新乘flagNew
* 自顶向下：检查内存单元是否与flagNew相等
*/
static ENUM_CM_RETURN s_Abraham_dec(IN CM_UINT8* pStart, IN CM_UINT8 *pEnd, CM_UINT8 flagPre, CM_UINT8 flagNew)
{
    volatile CM_UINT8* p = NULL;
    CM_UINT32 val = 0u;
    /*- 初始化为自检失败 */
    ENUM_CM_RETURN rt = ENUM_CM_FALSE;

    CM_ASSERT(pStart >= pEnd, MEMORY_CHECK_MODE, DARK_FAULT_CODE_FUN_ORDER_6, TSCP_DARK_ASSERT_1);
    CM_ASSERT((CM_UINT64)pStart < CM_UINT64_MAX, MEMORY_CHECK_MODE, DARK_FAULT_CODE_FUN_ORDER_6, TSCP_DARK_ASSERT_1);
    CM_ASSERT((CM_UINT64)pEnd > 0u, MEMORY_CHECK_MODE, DARK_FAULT_CODE_FUN_ORDER_6, TSCP_DARK_ASSERT_1);

    /*- 从高地址开始 | 遍历至低地址 | 检查下一内存单元 */
    for (p = pStart; p >= pEnd; --p) /* parasoft-suppress MISRA2004-17_1 "提高代码执行效率" */
    {
        /*- 读取内存单元 */
        val = *p;
        /*- 内存数值是否与预期一致 */
        if (val == flagPre)
        {
            /*- 更新内存数值 */
            *p = flagNew;
        }
        else
        {
            /*- 退出循环 */
            break;
        }

    }
    /*- 自顶向下的遍历是否成功 */
    if (p < pEnd)
    {
        /*- 从低地址开始 | 遍历至高地址 | 检查下一内存单元 */
        for (p = pEnd; p <= pStart; ++p) /* parasoft-suppress MISRA2004-17_1 "提高代码执行效率" */
        {
            /*- 读取内存单元 */
            val = *p;
            /*- 内存数值是否与预期不一致 */
            if (val != flagNew)
            {
                /*- 退出循环 */
                break;
            }
            else
            {
            	/*- 无处理 */
            }
        }
        /*- 自顶向下的遍历是否成功 */
        if (p > pStart)
        {
            /*- 自检成功 */
            rt = ENUM_CM_TRUE;
        }
        else
        {
        	MSCP_LOG_MSG("error \r\n");
        	/*- 无处理 */
        }
    }
    else
    {
    	/*- 无处理 */
    }
    /*- 返回自检结果 */
    return rt;
}


/*
* @brief Abraham算法步骤57
* @param pStart 起始地址(低地址）
* @param pEnd 终止地址（高地址）
* @return 检查结果
* - ENUM_CM_TRUE 成功
* - ENUM_CM_FALSE 失败
* @details
* 自底向上：检查内存单元是否为flagPre，然后将内存单元更新为flagNewk后恢复至flagPre
* 自顶向下：检查内存单元是否为flagPre
*/
static ENUM_CM_RETURN s_Abraham_inc2(IN CM_UINT8* pStart, IN CM_UINT8* pEnd, CM_UINT8 flagPre, CM_UINT8 flagNew)
{
    volatile CM_UINT8* p = NULL;
    CM_UINT32 val = 0u;
    /*- 初始化为自检失败 */
    ENUM_CM_RETURN rt = ENUM_CM_FALSE;

    CM_ASSERT(pStart <= pEnd, MEMORY_CHECK_MODE, DARK_FAULT_CODE_FUN_ORDER_7, DARK_FAULT_CODE_FUN_ORDER_1);
    CM_ASSERT((CM_UINT64)pStart > 0u, MEMORY_CHECK_MODE, DARK_FAULT_CODE_FUN_ORDER_7, DARK_FAULT_CODE_FUN_ORDER_1);
    CM_ASSERT((CM_UINT64)pEnd < CM_UINT64_MAX, MEMORY_CHECK_MODE, DARK_FAULT_CODE_FUN_ORDER_7, DARK_FAULT_CODE_FUN_ORDER_1);

    /*- 从低地址开始 | 遍历至高地址 | 检查下一内存单元 */
    for (p = pStart; p <= pEnd; ++p) /* parasoft-suppress MISRA2004-17_1 "提高代码执行效率" */
    {
        /*- 读取内存单元 */
        val = *p;
        /*- 内存数值是否与预期一致 */
        if (val == flagPre)
        {
            /*- 更新内存数值 */
            *p = flagNew;
            *p = flagPre;
        }
        else
        {
        	MSCP_LOG_MSG("val 0x%x 0x%x\r\n",val,flagPre);
            /*- 退出循环 */
            break;
        }

    }
    /*- 自底向上的遍历是否成功 */
    if (p > pEnd)
    {
        /*- 从高地址开始 | 遍历至低地址 | 检查下一内存单元 */
        for (p = pEnd; p >= pStart; --p) /* parasoft-suppress MISRA2004-17_1 "提高代码执行效率" */
        {
            /*- 读取内存单元 */
            val = *p;
            /*- 内存数值是否与预期不一致 */
            if (val != flagPre)
            {
            	MSCP_LOG_MSG("val 0x%x 0x%x\r\n",val,flagPre);
                /*- 退出循环 */
                break;
            }
            else
            {
            	/*- 无处理 */
            }
        }
        /*- 自顶向下的遍历是否成功 */
        if (p < pStart)
        {
            /*- 自检成功 */
            rt = ENUM_CM_TRUE;
        }
        else
        {
        	/*- 无处理 */
        }
    }
    else
    {
    	MSCP_LOG_MSG("error 3\r\n");
    	/*- 无处理 */
    }
    /*- 返回自检结果 */
    return rt;
}

/*
* @brief Abraham算法步骤68
* @param pStart 起始地址（高地址）
* @param pEnd 终止地址（低地址）
* @return 检查结果
* - ENUM_CM_TRUE 成功
* - ENUM_CM_FALSE 失败
* @details
* 自顶向下：检查内存单元是否为flagPre，然后将内存单元更新为flagNew后恢复至flagPre
* 自底向上：检查内存单元是否为flagPre
*/
static ENUM_CM_RETURN s_Abraham_dec2(IN CM_UINT8* pStart, IN CM_UINT8* pEnd, CM_UINT8 flagPre, CM_UINT8 flagNew)
{
    volatile CM_UINT8* p = NULL;
    CM_UINT32 val = 0u;
    /*- 初始化为自检失败 */
    ENUM_CM_RETURN rt = ENUM_CM_FALSE;

    CM_ASSERT(pStart >= pEnd, MEMORY_CHECK_MODE, DARK_FAULT_CODE_FUN_ORDER_8, TSCP_DARK_ASSERT_1);
    CM_ASSERT((CM_UINT64)pStart < CM_UINT64_MAX, MEMORY_CHECK_MODE, DARK_FAULT_CODE_FUN_ORDER_8, TSCP_DARK_ASSERT_1);
    CM_ASSERT((CM_UINT64)pEnd > 0u, MEMORY_CHECK_MODE, DARK_FAULT_CODE_FUN_ORDER_8, TSCP_DARK_ASSERT_1);

    /*- 从高地址开始 | 遍历至低地址 | 检查下一内存单元 */
    for (p = pStart; p>= pEnd; --p) /* parasoft-suppress MISRA2004-17_1 "提高代码执行效率" */
    {
        /*- 读取内存单元 */
        val = *p;
        /*- 内存数值是否与预期一致 */
        if (val == flagPre)
        {
            /*- 更新内存数值 */
            *p = flagNew;
            *p = flagPre;
        }
        else
        {
            /*- 退出循环 */
            break;
        }

    }
    /*- 自顶向下的遍历是否成功 */
    if (p < pEnd)
    {
        /*- 从低地址开始 | 遍历至高地址 | 检查下一内存单元 */
        for (p = pEnd; p <= pStart; ++p) /* parasoft-suppress MISRA2004-17_1 "提高代码执行效率" */
        {
            /*- 读取内存单元 */
            val = *p;
            /*- 内存数值是否与预期不一致 */
            if (val != flagPre)
            {
                /*- 退出循环 */
                break;
            }
            else
            {
            	/*- 无处理 */
            }
        }
        /*- 自顶向下的遍历是否成功 */
        if (p > pStart)
        {
            /*- 自检成功 */
            rt = ENUM_CM_TRUE;
        }
        else
        {
        	/*- 无处理 */
        }
    }
    else
    {
    	/*- 无处理 */
    }
    /*- 返回自检结果 */
    return rt;
}

