概述
目前越来越多的微控器(MCU)应用需要使用到复杂的算法及中间件解决方案(middleware solution),因此,如何保护软件方案商开发出来的核心算法等知识产权代码(IP-Code),便成为微控制器应用中一项很重要的课题。因为这一重要的需求,AT32F423系列提供了安全库区(SLIB)的功能,以防止重要的IP-Code被终端用户的程序做修改或读取,进而达到保护的目的。本文档将详细阐述AT32F423系列安全库区的应用原理和软件使用方法。
应用原理
安全库区的应用原理
下图是包含安全库区的主闪存区映射示意图,安全库区的程序代码可以很容易地被终端用户调用并执行, 但不能直接被读取,因而达到保护的功能。图1. 带有安全库区的主闪存区映射安全库区的范围大小是以扇区(sector)为单位做设定,每一扇区的大小以实际MCU型号为准。表1是AT32F423系列各型号的主闪存大小、每扇区大小及可设置范围。另外启动程序代码区在开启了主存扩展功能后,整个20KB区域也是可以作为安全库区。表1. AT32F423各型号闪存大小总表
如何启动安全库区保护
默认状态下,安全库区设定寄存器始终是不可读且被写保护。要想对安全库区设定寄存器进行写操作,首先要对安全库区设定寄存器解锁,对SLIB_UNLOCK寄存器写入解锁0xA35F6D24值,通过查看SLIB_MISC_STS寄存器的SLIB_ULKF位确认解锁成功,随后便允许对安全库区设定寄存器写入设定值。启动主闪存安全库区的步骤如下:
注意事项:
关于安全库区设定寄存器的详细说明,请参阅AT32F423系列技术手册。启动安全库区的程序可参考安全库区应用范例project_l0中位于main.c中的slib_enable()函数。亦可使用雅特力的ICP或ISP刻录工具做设定,后面章节将会有详细的说明。
如何解除安全库区保护
当安全库区的保护功能被启动后,可以透过在SLIB_PWD_CLR寄存器写入先前设置的密码来解除保护功能。解除安全库区的保护时,芯片将会执行主闪存的整片擦除(包含安全库区的内容)。解除主闪存安全库区的步骤如下:
编排及执行安全库区的程序
如前面章节所提到,在指令安全库区(SLIB_INSTRUCTION)内的的程序代码可以被MCU经由I-Code总线抓取,但不能经由D-Code总线以读取数据的方式去读出,这样的保护是全面性的,也就是说在指令安全库区之内的程序代码,也不能读取同样被放置在指令安全库区之内的数据,例如C程序代码常被编译成的文字池(literal pool)、分支表(branch table)或常数(constant)等之类当指令被执行时会经由D-Code总线去读取的数据。这代表指令安全库区之内只能放置指令,不能放置任何数据。因此用户在编排要放置在指令安全库区之内的程序代码时,必须配置编译程序(compiler)的设定去产生只执行(execute-only)的代码以避免上述那些型态的数据产生。图2及图3是一般常见的文字池跟分支表的例子:switch()是C程序中常用的跳转指令,此例子中的sclk_source变量是去读取CRM_CFG寄存器,图2可看到编译出来的汇编代码(assembly code) “LDR R7, [PC, #288]”,会用程序计数器(program counter, PC)间接寻址的方式去取得CRM_CFG寄存器的地址,而CRM_CFG的地址会被以常数的方式存放在邻近的指令区(也在指令安全库区之内),因此执行switch()指令时就会发生数据的读取。如果指令安全库区内有这类的程序代码,在执行的时候就会产生错误。第三章的范例程序将会说明如何设定编译程序的配置来避免这样的问题。图2. 文字池例子(1)图3. 文字池例子(2)
不可将中断向量表设置为安全库区的指令区
中断向量表包含每个中断处理程序的入口点地址,由MCU通过D-Code总线读取。通常,中断向量表位于主闪存第一扇区(sector 0)的起始地址0x08000000,因此在设置指令安全库区时,必须遵守以下的规则:
安全库区代码与用户区代码的关联性
受安全库区保护的程序代码(IP-Code)可以从位于用户代码区(安全库区之外的区域)的函数库中调用函数。在这种情形下,IP-Code将会包含这些函数的地址,允许PC(程序计数器)在执行IP-Code时跳转到这些函数。一旦安全库区被启动,这些函数的地址就不能被改变,此时,这些位于用户代码区的函数的地址就必须固定下来,否则PC将跳转到错误的地址而无法正常工作。因此在设置安全库区的时候,应该将所有与IP-Code相关联的函数都一起编排到安全库区之内以避免此情况发生。下图显示出一个被保护的函数Function_A()调用到用户区内的函数Function_B()的例子。图4. 安全库区的函数调用用户区函数的例子此外,另一个最常见的情形就是使用到C语言的标准函式库,例如memset()及memcpy()这类函数。如果IP-Code跟用户区代码都有调用到这类函数,就会有上述问题的困扰。列举两种常用的解决方法:1) 将其编译到安全库区范围内,具体如何实现可以查看keil或IAR的相关文档。2) 避免在IP-Code内使用C的标准函式库,若非要使用,就必须将用到的函数改写为其他名称,以下是一个范例,在IP-Code 中写一个my_memset()函数取代原先的memset()。图5. 自定义函数范例
方案商和终端用户代码整合及下载操作流程
方案商和终端用户的代码设计完成后,需要下载到同一个MCU中,这就涉及到各自代码的安全性问题。以下列举两种常用下载操作流程供用户参考,仍然是以上面Project_L0和Project_L1为例。操作中涉及到AT-Link的离线下载模式,详细描述可以参考ICP使用文档及AT-Link使用文档。
方案商和终端用户代码分别烧录
方案商先烧录SLIB代码到MCU,然后终端用户再烧录应用代码到MCU,步骤如下:(1) 方法A:方案商将编译完成的工程中SLIB部分的代码通过ICP截取保存成BIN或者HEX档:先将整个工程下载到MCU(此时不配置SLIB及FAP等信息),然后通过存储器读取功能读取对应SLIB部分代码(0x08001000~0x08002FFF),再通过ICP软件操作文件-存储器数据另存为将其保存为BIN或者HEX,例程中BIN档命名为slib.bin,如下图。图42. 保存SLIB代码方法B:方案商将编译完成的工程直接产生bin格式的文件,取其中SLIB区域对应的一段,例如在KEIL工程中,user选项中添加fromelf.exe --bin --output .\Listings\@L.bin !L,生成对应固件的bin档,将对应的SLIB段文件添加后缀名.bin格式,本例中改为ER_SLIB_INSTRUCTION.bin和ER_SLIB_READ_ONLY.bin,对应的就是0x08002000地址段的SLIB-INSTRUCTION文件和0x08001000地址段的SLIB-READ-ONLY文件,如下图图43. 生成SLIB代码部分bin文件(2) 将bin通过ICP工具,在线烧录到MCU,如下图图44. ICP在线烧录MCU(3) 或者通过ICP工具配置成离线项目工程保存到AT-Link,然后经过AT-Link离线烧录到MCU,保存离线项目工程如下图。图45. AT-Link离线烧录到MCU(4) 经过步骤2或者步骤3,终端用户拿到烧录好SLIB部分的MCU,此时SLIB状态会显示为已启用,终端用户通过在线烧录或者离线烧录应用代码到MCU完成整个过程,在线烧录如下图。图46. 终端用户烧录代码到MCU
方案商和终端用户代码合并烧录
方案商的SLIB代码和终端用户的应用代码整合到一个离线项目工程中,通过AT-Link离线烧录一次下载到MCU,步骤如下:(1) 方案商将编译完成的工程按照上一章节所述方法处理,得到SLIB部分的BIN档。(2) 方案商通过ICP制作离线项目工程并保存到PC,可以根据最终需求配置各种参数,比如限制下载次数、项目文件绑定AT-Link、下载完成后开启FAP等,保存离线项目工程如下图注意:离线项目工程本身已经经过加密,为进一步提升安全性,方案商还可以将slib.bin制作成加密的slib.benc文件再添加到离线项目工程中,但此时的离线项目工程只能在对应匹配加密秘钥的AT-Link上才能使用图47. 制作离线项目工程(3) 终端用户拿到该离线项目工程,用ICP打开项目文件,通过添加文件功能,可以添加应用代码部分到该离线项目工程,然后再保存到PC或者直接存储到AT-Link,通过执行离线下载完成操作,项目文件添加方法如下图。注意:为防止代码泄露被破解等风险,离线项目工程添加代码文件时其余配置都不可更改,所以需要方案商预先将最终配置设置好图48. 添加项目文件
全部0条评论
快来发表一下你的评论吧 !