摘要
在学习ISO 26262标准的过程中,我们会经常提到“功能安全生命周期“这个概念,对于生命周期这个词,标准的定义是“相关项从概念到报废的全部阶段“。
为了了解生命周期这个概念,我们分别从项目(产品)层面和公司层面这两个角度进行说明。
一. 产品层面的功能安全生命周期
我们以图1中系统层面产品作为示例来进行说明。
(图1)
这张图中,我们可以看到对于产品的开发阶段,我们划分了四个阶段(第一行),分别是产品立项阶段,概念阶段,开发阶段以及工程和生产阶段。对于活动的执行部门(第一列)我们也进行了划分,部门的划分大体可以分为需求,设计,生产这三个大类,因为每个公司对于部门职责的划分都是各不相同,所以这里我们重点关注产品的四个开发阶段。
1-立项阶段:这个阶段我们的主要活动就是根据客户初期的需求或者市场调研结果判断是否立项,项目的相关管理人员也会在这个阶段明确;
2-概念阶段:立项成功后,概念阶段我们就要开始制定项目计划和安全计划,对项目所有的活动进行统一规划,对于功能安全而言,这个阶段我们有两个重要的活动进行执行,分别是影响分析(对于部分复用项目安全活动的识别)和SEooC(判断项目是否是定制开发),这两个活动都会影响到安全计划中对于安全活动的范围判定以及安全需求的制定。
就拿影响分析而言,影响分析是分析新项目在旧项目的基础上需要做哪些方面的修改,如果进行修改,会对旧项目的哪些WP(工作成果)造成什么样的影响,这些修改工作什么时候开始进行,由谁来执行等信息都会在安全计划中更新。比如旧项目是ASILB等级,而新项目是ASILD等级,因为客户对产品的随机硬件失效率提出了更高的要求,并且新旧产品在功能层面的需求相同,所以考虑在原有架构基础上新增一些安全机制尝试实现新的要求,通过影响分析活动判断下来部分IP的详细设计specification是可以直接复用;而诸如需求Spec,架构设计,FMEDA等活动需要在原有文档基础上进行修改;像FTA,高ASIL等级对应的测试验证活动等,由于旧项目ASIL较低,所以当时是没有执行,现在ASILD项目中,我们就要新增这些活动,并输出相对应的文档。
而对于SEooC而言,它就直接决定了我们的安全要求的制定,要么是客户定制提出产品需求,要么是SEooC假设获得需求,这些都会体现在安全计划的内容中。
3-开发阶段:对于图1中的示例,产品涉及硬件和软件的开发,对于硬件和软件而言,各自开发过程基本相同,从获得HSR/SSR(硬件安全需求/软件安全需求)→架构设计→详细设计→集成设计,以及每个环节的验证活动,包括我们重点关注的FMEA,FTA,DFA,FMEDA这些安全分析活动也都是在这个阶段来执行的。此阶段的活动就是为了在技术层面将产品需求实现。
4-工程和生产阶段:当上阶段的开发工作结束后,我们就要将设计转化为实体的商品,此时我们便要联系生产和封装厂进行生产活动,这里就要包括对生产工艺的要求,生产的计划安排以及生产过程的其他管理活动。生产结束后客户在使用过程中遇到的一些调试,安装等问题要求,产品出现质量问题的售后服务以及产品在达到使用寿命后所要采取的必要保费措施,都会记录在这个阶段。以上内容就是一个系统层面产品生命周期中会出现的活动。
二. 组织层面的安全生命周期
公司层面的安全生命周期相较于产品层面就没有那么复杂,对于公司而言生命周期其实就是公司可能会涉及的标准范围,也就是标准part2-5.4.6(独立于项目的安全生命周期裁剪)的要求。下图2是ISO 26262经常会看到的一副标准章节图。
这里面将标准所有的章节及对应的安全活动进行了展现, 可以简单地理解上图就是功能安全在公司层面最完整的生命周期,不同的公司的安全生命周期只会比此范围小,不会超越此图的范围,不同公司将此图中不涉及的章节或者安全活动裁剪以后的结果就是该公司组织层面的生命周期,已下表中的内容为例给大家进行说明。
表格前两列列举了标准从part2-part9的主要内容(这里暂时只考虑与实际项目实施强相关的几个部分),后4列我们是划分了四种类型的公司,标记了它们对应ISO 26262标准生命周期常见的几种情况。
1-对于OEM厂商而言,它们属于汽车E/E开发需求的发起者,而且是产业链的最终集成者,所以OEM是会涉及标准的所有章节,因此他们的生命周期就是完整的ISO 26262范围。
2-对于系统集成商而言,他们的产品一般会先集成到Tire1&Tire2的产品中,然会才会应用到整车上进行使用,他们一般不会直接承担整车的某项功能,所以标准part3的活动对于他们而言是不涉及的,因此在他们的生命周期中是要裁剪掉的,而对于系统的设计工作(part4),软件硬件的设计工作(part5&6),支持部分(part8中的安全需求管理,DIA,配置管理,变更管理等),安全分析(part9)这些都有可能会涉及,因此在他们生命周期中这些都是要保留下来的。另外对于部分系统开发公司,可能会存在没有产品的实际生产能力,所以part7对于系统层面有被裁剪掉的可能性。
3-对于一个纯硬件公司,首先part2,part8的管理和支持内容肯定是要保留,并且因为它们是专业的硬件设计公司,所以part5的设计内容以及part9的安全分析内容也是要保留,因为是纯硬件公司,所以软件部分的part6则需要裁剪掉,part3因为是相关项层面的活动,所以也不会涉及。而硬件公司,可能会去开发通用组件而假设客户的需求,所谓的客户其实就是系统层面的集成商,因此就可能会通过SEooC假设到系统层面的需求,也就相当于part4-6的内容,因此硬件公司关于part4是可能会设计到的。Part7就和系统层面的理由一致,可能会涉及到,也可能会被裁剪掉。
4-对于芯片生产,封装厂,因为不涉及功能安全的设计环节,所以part3—part6都不涉及,会被裁剪掉,与其相关的就是part2的管理部分,part7的生产部份,part8的支持部分。
以上内容就是生命周期在产品层面和组织层面的内容。
(转自Munik秒尼科技术微信公众号)
根据图一软件开发阶段V模型,软件单元设计和实现之后,需要对相应的软件设计进行测试验证即V模式右边内容。具体包括:软件单元验证、软件集成和验证、嵌入式软件验证。本文着重阐述功能安全软件开发阶段中这三个阶段的测试验证活动。
图一:软件开发阶段V模型
1、软件测试验证方法
1.1 软件测试验证对象
软件单元验证、软件集成和验证、嵌入式软件验证分别对应的不同的测试对象,具体如下图所示:
图二:软件测试验证对象
1.2 软件测试验证方法
ISO 26262-6:2018 从第9章节到第11章节分别对软件单元验证、软件集成和验证、嵌入式软件验证这三部分进行了详述,其中对根据ASIL等级推荐了不同的验证方法,如下图所示:
图三、软件单元验证方法
图四、软件集成验证方法
图五、嵌入式软件的测试方法
从图三、图四、图五可以看到软件单元设计的验证以走查、检查、审查、分析、测试等为主要验证方法;软件集成验证以静态分析、资源评估(主要包括消耗的CPU资源、RAM、ROM等)、测试等为主要验证方法;嵌入式软件的测试方法主要用测试来进行验证。虽然属于软件开发中的不同子阶段,但是很多测试方法是共同的,比如故障注入测试、接口测试、基于需求的测试。这里可以从测试类型的角度,将测试归纳为静态分析测试和动态分析测试。
1.2.1 静态分析:
静态分析是指不用执行程序的测试,对程序文件进行跟踪,即可以在运行程序之前的早期阶段检测分析。它主要采用代码走查、技术评审、代码审查等方式对软件单元或者软件产品进行测试。验证方法有走查、结对编程、检查、控制流分析、数据流分析、静态代码分析,主要集中在软件单元验证和软件集成验证活动中。其中静态代码分析最为主要,其主要目的是检查代码编写是否符合特定的编程规则。对于大部分车辆控制器代码而言,静态代码分析,即C代码静态分析(如果基于模型开发,则是自动生成的代码),主要是保证代码满足MISRA C(Motor Industry Software Reliability Association, 汽车工业软件可靠性协会)相关的要求。
静态代码分析一般可以直接采用自动化检测软件,例如SIMULINK, Model Advisor; Vector, VectorCAST; Perforce, Helix QAC等,通过配置代码检测规则,然后导入源文件进行自动化分析,如果不满足相关要求,则需要对代码进行修改直至满足为止。最终输出静态代码分析报告给予功能安全软件设计验证提供依据。
1.2.2 动态分析:
动态分析是指测试程序的动态形式,对运行着的程序进行跟踪,通过观察程序运行的实际结果来发现错误和缺陷。它包括的验证方法有:基于需求的验证、接口测试、背靠背测试、故障注入测试等,主要集中在软件集成验证和嵌入式软件验证活动中。动态分析在测试环节具体现如下图:
图六、动态分析测试
在给出的验证方法中,测试占据很大部分,如何进行测试,更需要关注具体的测试用例,它规定测试的测试方法、测试环境、测试设备和工具、测试步骤、判断准则、预期结果等等。
2 软件测试用例导出方法
动态分析测试基本上都需要用到测试用例,如何导出测试用例,用尽可能少的测试用例,覆盖尽可能多的测试场景,这个是对功能安全测试工程师一个很高的要求。ISO 26262-6:2018中分别给出了软件单元、集成测试、嵌入式软件测试用例导出方法,这里归类如下图所示:
图七、测试用例导出方法
其中:
等价类的生成和分析,可以基于划分输入输出来识别等价类,为每个等价类选择一个有代表性的测试值;边界值分析主要用于接口测试,接近边界的值、与边界交叉的值及超出范围的值;错误推测法可基于经验学习中收集的数据和专家判断的数据做为依据进行测试;软件操作用例分析可以包括现场软件更新或者嵌入式软件在不同操作模式下的安全相关行为分析,例如,启动、诊断、降级、断电(进入睡眠状态)、通电(唤醒)、校准、不同ECU 之间的模式下的安全行为分析。
如下图给出了测试用例的设计示例可供参考:通过变化f_in_cell_voltage的输入数值,观察b_out_charging_enable输出数值的结果:
图八、测试用例示例
3 软件安全测试的完整性
为了评估验证的完整性并提供证据证明已有测试用例已充分实现相应测试目标,必须对测试完整性进行评估,这里就得提到结构覆盖率这个概念。结构覆盖率用于度量我们设计的测试用例在多大程度上可以覆盖我们的代码,测试人员可以创建代码覆盖缺失的测试用例,以增加覆盖率。在ISO 26262-6:2018中对软件单元,集成软件的测试覆盖率提出了相应要求,具体包括:
图九、结构覆盖率在软件验证过程中的要求
可以看出,软件单元层面结构覆盖率多基于语句、分支等最基本的代码组合部分测试,而集成后的软件架构层面的结构覆盖率多基于函数,其层级更高。二者逐步递进,可以有效的评估软件安全测试的完整性和充分性。
其中:
函数覆盖率和调用覆盖率很好理解,分别用来统计代码中所有函数是否被测试用例执行的比例和执行测试用例时每个函数是否被调用的比例。下面重点介绍一下:语句覆盖率、分支覆盖率以及MC/DC(修改/判定条件覆盖率),因为这三个覆盖率最容易被混淆。
3.1 语句覆盖率
语句覆盖率用于统计每个代码语句被测试用例执行的比例,主要从未执行的语句,死代码、未执行的分支三个范围综合考虑的。
示例:
源代码:为一个简单的计算两个数值之和的函数
方案1:
如果A=3,B=9
代码执行如下图所示:黄色标记的是根据输入值后执行的语句,已执行语句=5,语句总是=7,所以语句的覆盖率:5/7=71%。
方案1:
如果A=-3,B=-9
代码执行如下图所示:黄色标记的是根据输入值后执行的语句,已执行语句=6,语句总是=7,所以语句的覆盖率:6/7=85%。
但是总体的来说,所有的未覆盖的语句都被第二种方案所覆盖,如果覆盖到所有测试边界就可以认为覆盖率为100%。
3.2 分支覆盖率
分支覆盖率用于统计每个判定分支被测试用例执行的比例,确保来自每个分支的每个条件至少执行一次。具体指在if,case,for,forever,while等语句中各个分支的执行情况。
这里还是依语句覆盖率示例代码为例,计算两个数值之和的函数对应的控制流程图如下
从流程图可以看出图中给出两个执行路径1-2-3-4和1-2-5-6。所以我们在设计测试用例时需要考虑把两条路径都要覆盖到。
测试用例:
这里的分支覆盖率一定不可以约分。1/2怎么来的呢?1代表当前覆盖了一条语句,2代表这个程序一共有两个分支。
3.3 MC/DC(修改/判定条件覆盖率)
MC/DC(修改/判定条件覆盖率) 用于判断类代码覆盖检测,相对比较难理解。它是对分支测试的进一步补充,要求在一个程序中每一种所有可能的输入和输出至少出现一次,并且要求判定中的每一个条件必须能够独立影响判定输出,简单可以理解在其他条件不变的前提下,仅改变条件中一个值,而使判定结果改变。
示例:
用例:
对于条件A,用例1和用例2,A取值相反,B和C相同,判定结果分别为1和0;
对于条件B,用例1和用例3,B取值相反,A和C相同,判定结果分别为1和0
对于条件C,用例3和用例4,C取值相反,A和B相同,判定结果分别为0和1。
理论上,对于三个输入判定条件(A, B, C),一共存在8种测试Case,为实现MC/DC全覆盖,然而仅仅用了4个案例就实现了MC/DC全覆盖,使用最少的测试用例达到最高的覆盖率,不仅节省了成本还节省了时间。
总之,结构覆盖率不需要一味追求100%,高结构覆盖率并不完全说明代码已经进行高质量充分测试,它只说明哪些代码没有被测试用例有效执行。结构覆盖率测试可以帮我们反推前期测试用例设计是否充分,是否存在盲点,哪些地方需要进行补充,增加测试完整性。结构覆盖率测试并不能解决软件事先没有考虑到的情形及功能不足。
4 软件测试的环境
在进行测试验证时我们还需要考虑测试环境和目标环境之间的差异,以便在后续测试阶段的目标环境中定义额外的测试。不同阶段的测试对应着不同的测试环境,如下图所示:
图十、软件测试环境要求
其中:模型在环测试主要验证基于模型开发的软件单元和产品;电子控制单元网络测试环境主要用于测试功能安全对于网络安全的影响;硬件在环测试主要应用于接口测试验证软件设计是否符合软硬件接口规范。
关于功能安全软件开发阶段-软件测试验证的分享就到这里了,无论是最初的设计还是后期的验证环节,我们需要时刻规范开发过程中的每一个子阶段,才能避免因软件设计而造成的系统性失效。
(转自Munik秒尼科技术微信公众号)
在前面的文章中,我们介绍了在开发调试过程中如何在IAR Embedded Workbench中进行堆栈静态分析和动态监控,然后设置合理的堆栈大小,避免堆栈溢出。但是即使设置了合理的堆栈大小,在程序运行时最好有对应的失效安全(fail-safe)策略:如果在运行过程中出现堆栈溢出,程序应该要能检测到并执行相应的策略。
本文主要介绍如何在程序运行时进行堆栈溢出检测及检测到堆栈溢出之后的失效安全策略。
程序运行时堆栈溢出检测主要通过检查对应的堆栈指针(SP)是否超出指定的堆栈范围来实现,一般可以分为硬件检测和软件检测。
硬件堆栈溢出检测的原理:设置对应的硬件单元,如果在程序运行过程中,SP超出指定的堆栈范围,会触发对应的硬件错误。目前主要有如下两种方式:
ARMv8-M架构中包含了堆栈限制寄存器(Stack Limit registers),当SP的值小于(ARMv8-M架构中堆栈是向下生长的)对应Stack Limit registers的值时,会触发UsageFault或者HardFault:
为了提高系统的安全性,越来越多的MCU集成了内存保护单元(MPU:Memory Protection Unit),可以通过设置MPU的属性,当SP访问超出指定的堆栈范围时,产生MemManageFault或者HardFault:
软件堆栈溢出检测的原理:在程序开始之前,往堆栈防护区域填充特定的值(比如0xCD),然后在程序运行时去检查堆栈防护区域中之前填充的值是否被篡改:如果被篡改了,说明堆栈溢出。
通常情况下,RTOS会提供任务堆栈溢出检测功能,只需要使能对应的宏定义,打开堆栈溢出检测功能。当检测到堆栈溢出时,RTOS会调用相应的堆栈溢出钩子函数(hook)。
注意:RTOS一般会计算各个任务堆栈的使用情况,所以在新建任务时,RTOS会把任务堆栈所有区域都填充特定的值,然后在运行过程中去检测和计算对应的堆栈使用情况。
在RTOS里面进行任务堆栈溢出检测一般需要如下操作(下面以Azure RTOS为例):
/* Determine whether or not stack checking is enabled.
By default, ThreadX stack checking is disabled.
When the following is defined, ThreadX thread stack checking is enabled.
If stack checking is enabled (TX_ENABLE_STACK_CHECKING is defined),
the TX_DISABLE_STACK_FILLING define is negated,
thereby forcing the stack fill which is necessary for the
stack checking logic. */
#define TX_ENABLE_STACK_CHECKING
void my_stack_error_handler(TX_THREAD *thread_ptr);
/* Register the "my_stack_error_handler" function with ThreadX
so that thread stack errors can be handled by the application. */
status = tx_thread_stack_error_notify(my_stack_error_handler);
系统堆栈溢出检查需要开发人员手动添加对应的代码:在程序开始之前,往堆栈防护区域填充特定的值(比如0xCDCDCDCD),然后在程序运行时去检查堆栈防护区域中之前填充的值是否被篡改。
#define STACK_FILL_PATTERN 0xCDCDCDCD
/* Linker generated symbols */
extern uint32_t CSTACK$$Base;
/* Fill the stack base with dedicated pattern */
*((uint32_t *) &CSTACK$$Base) = STACK_FILL_PATTERN;
/* Check system stack overflow */
/* If the filled pattern is changed, there is stack overflow */
if(STACK_FILL_PATTERN != *((uint32_t *) &CSTACK$$Base))
{
}
注意:软件堆栈溢出检查由于是通过软件代码进行检测,可能没有那么及时,也有可能在堆栈溢出的地方已经造成了其它的硬件错误(比如从堆栈POP出的PC指向了不可执行的地址)。
前面介绍了程序运行时进行堆栈溢出检测的方法。那么当检测到堆栈溢出之后程序应该怎么处理呢?
由于堆栈溢出可能会造成程序运行需要的重要数据的破坏,而这种破坏是未知的。所以当发生堆栈溢出时,程序通常是很难继续正常运行的,往往需要通过系统复位来重新回到正常的状态。但是需要注意的是,在系统复位之前,需要确保系统进入安全状态,避免造成更严重的损害。下面是发生堆栈溢出之后一般的处理策略:
本文主要介绍了如何在程序运行时进行堆栈溢出检测及检测到堆栈溢出之后的失效安全策略。开发人员可以根据对应系统的具体情况选择合适的方法进行程序运行时堆栈溢出。当检测到堆栈溢出之后,程序需要执行相应的失效安全策略确保系统能够安全地回到正常的运行状态。
参考文献:
我们提供IAR Embedded Workbench for Arm、RISC-V、STM8、Renesas RX、RL78和RH850 经过认证的构建工具链,用于符合IEC 61508、ISO 26262、EN 50128和IEC 62304标准的安全关键型应用。在本文中,我们将介绍认证的含义,以及您如何在自己的项目中利用这种认证。无论您的产品有没有计划进行正式认证,包含的功能安全服务都具有很大的价值。
安全认证的正式标准已经发布多年,但在过去的几年中,特别是在嵌入式领域,人们对这些标准的兴趣和实际使用程度正在显著增加。人们对认证和经过认证的终端产品的兴趣日益浓厚,部分原因是法律要求,但对生产企业来说,获得安全认证意味着获得市场竞争力。
与许多功能安全相关的国际综合标准IEC 61508,经过了多次修订,于2010年发布了第二版。这个标准以及它所衍生的标准,现在广泛应用于对可靠性和安全性有要求的行业,如过程工业、铁路和自动化等,比如ISO 26262用于汽车领域、EN 50128用于铁路应用、IEC 62304用于医疗软件和医疗设备。
如果您即将启动一个具备安全关键功能或功能安全要求的项目,您可能已经意识到您所使用的开发工具必须以某种方式经过资格认证,以适用于与安全相关的开发。如何验证开发工具的具体要求取决于您所遵循的标准以及在某种程度上产品故障可能引发的严重程度。这还与工具的性质有关,例如,生成进入产品的代码的编译器比源代码度量工具更难认证,而源代码度量工具比版本控制系统或需求管理系统更难认证。
不同的标准对安全完整性(即产品的关键程度) 有不同的定义,并且这些标准在工具的分类上也有所不同。以IEC 61508为例,它规定了编译器等工具需要经过认证,尽管并没有明确定义“认证”的具体含义。此外,该标准还要求这些工具必须经过验证,以确保它们符合相关的规范或文档。最糟糕的情况是,这意味着您必须在自己的项目中全面测试这些工具,除非能够提供充分的测试证据。此外,您还需要评估该工具在项目中的依赖程度。
还需要考虑和评估的另一件事情是工具供应商支持工具的能力,最好能够在安全关键产品的整个生命周期内提供支持。
将所有这些放在一起可能会给您带来相当大的工作量,而这只是关于一个工具和一个项目的事情……这正是我们的工具链获得认证的背景。
我们用于安全关键开发的工具获得认证到底意味着什么呢?它意味着您为证明工具的使用合理性而必须做的工作量大大减少。因为独立的第三方机构TÜV SÜD 已经对我们的开发活动、问题处理程序以及测试和验证活动进行了评估,并认证了我们的工具符合IEC 61508、ISO 26262、EN 50128和 IEC 62304等安全标准的要求。这也意味着,如果您选择C或C++作为编程语言,我们的工具链是一个绝佳的选择。
那么,如果选择了经过认证的工具,就完事大吉了吗?
嗯…… 还需要考虑的一个重要的事情是工具链需要的支持级别以及您可以获得的支持级别。这不仅仅限于项目开发的时间,还包括产品的整个生命周期。如果工具旧了并且被新版本取代,工具供应商不一定会在旧版本工具上继续支持您。这种立场与典型的安全相关项目的需求背道而驰,因为在这些安全相关项目中,应尽量避免工具的更新。
如果之前认证过的工具的更新不仅仅包含错误修复(Bug Fix),还包含功能更新,那么这个更新是没有实际用途的,因为需要对工具更新进行重新认证或者进行详细的影响分析以及测试。
通过与开发安全相关的并且具有高可用性要求的软件或服务的客户多年合作,我们了解到,对“冻结”版本的支持至关重要。“冻结”版本指的是只接受错误修复而永远不添加新功能的工具版本。这种版本可以根据需要保持活跃并得到支持。过去,我们为需要特定“冻结”版本和相关支持服务的客户量身定制了特殊协议。现在,通过认证之后,我们有机会以简化的方式为所有使用IAR Embedded Workbench的功能安全版本的客户提供“冻结”版本和相关支持服务。
我们的安全解决方案包含了以下主要内容:
总之,选择经过认证的工具链可以使您轻松地在安全相关项目中使用它。选择包含适当支持服务的工具可以保护您的工具选择和投资。此外,即使您的产品没有直接的安全要求,但如果需要满足各种高完整性或高可用性要求,功能安全支持服务也可能同样非常有用。