本帖最后由 whong0951 于 2020-4-17 11:19 编辑
因为产品需要通过classb安全认证,所以这两天在把st的 X-CUBE-CLASSB库往工程里添加,因为我们产品使用的是stm105芯片,按照官网说明的X-CUBE-CLASSB version 2.2.0 supports the STM32L0, STM32L1, STM32L4, STM32L4+, STM32F0, STM32F1, STM32F2, STM32F3, STM32F4 and STM32F7 Series
下载了2.2.0版本的库,移植后进行调试时遇到了一些奇怪的问题,我在这里汇总一下:
1.代码优化问题
我把库的源代码抽出有影响部分的放在下面
#define init_control_flow() CtrlFlowCntInv = ~(CtrlFlowCnt = 0uL)
#define control_flow_call(a) CtrlFlowCnt += (a)
#define control_flow_resume(a) CtrlFlowCntInv -= (a)
/*--------------------------------------------------------------------------*/
/*------------------- CPU registers and flags self test --------------------*/
/*--------------------------------------------------------------------------*/
/* Initialization of counters for control flow monitoring */
init_control_flow();
control_flow_call(CPU_TEST_CALLER);
/* WARNING: all registers destroyed when exiting this function (including
preserved registers R4 to R11) while excluding stack pointer R13) */
if (STL_StartUpCPUTest() != CPUTEST_SUCCESS)
{
#ifdef STL_VERBOSE_POR
printf("Start-up CPU Test Failure\n\r");
#endif /* STL_VERBOSE_POR */
FailSafePOR();
}
else /* CPU Test OK */
{
control_flow_resume(CPU_TEST_CALLER);
#ifdef STL_VERBOSE_POR
printf(" Start-up CPU Test OK\n\r");
#endif /* STL_VERBOSE_POR */
}
函数STL_StartUpCPUTest() 功能是直接对r0~r12寄存器赋值0~12再读回,确认寄存器没有问题,但是在函数返回时却没有将寄存器的值还原。在-O3优化下,在执行control_flow_call(CPU_TEST_CALLER);时会将CtrlFlowCntInv 的地址存入r4寄存器中,但是r4寄存器的值会在执行STL_StartUpCPUTest() 后发生改变,导致执行到control_flow_resume(CPU_TEST_CALLER);时会直接对地址0x0000 0004进行赋值操作,产生HardFault。
2.对函数的返回结果检查问题
在进行RAM测试时,程序
/*--------------------------------------------------------------------------*/
/* --------------------- Variable memory functional test -------------------*/
/*--------------------------------------------------------------------------*/
#ifdef STL_EVAL_MODE
/* LED_VLM On for debug purposes */
BSP_LED_On(LED_VLM);
#endif /* STL_EVAL_MODE */
/* no stack operation can be performed during the test */
__disable_irq();
/* WARNING: Stack is zero-initialized when exiting from this routine */
if (STL_FullRamMarchC(RAM_START, RAM_END, BCKGRND) != SUCCESS)
{
#ifdef STL_VERBOSE_POR
/* restore interrupt capability */
__enable_irq();
对函数STL_FullRamMarchC()的返回结果进行检查时没有使用自定义的枚举类型,而是文件“stm32f1x.h”中的枚举类型
typedef enum
{
SUCCESS = 0U,
ERROR = !SUCCESS
} ErrorStatus;
但是函数STL_FullRamMarchC()内的返回结果却是
STL_FullRamMarchC
MOVS R4, #0x1 ; Test success status by default
__FULL_ERR
MOVS R4,#0 ; error result
__FULL_RET
MOVS R0,R4
BX LR ; return to the caller
与前面枚举结果的定义正好相反,导致检查成功时返回的却是错误的结果,令人疑惑的是这里if (STL_FullRamMarchC(RAM_START, RAM_END, BCKGRND) != SUCCESS)的处理方式与前文 if (STL_StartUpCPUTest() != CPUTEST_SUCCESS)并不一致,明明之前会使用自定义的枚举类型进行检查,到这里怎么又偷懒了?
很难理解一个用于安全认证的库会这么不严谨,我都开始怀疑它真的可以保证产品的安全性能么,还有就是这种安全认证库是否可以直接修改?修改后安全认证还有没有效果?
|