前言
这篇应用笔记主要在阐述AT32F413系列安全库区的应用原理、软件使用方法及范例程序。
支持型号
AT32F413xx
目录
1 概述 ......................................... 7
2 应用原理 .................................. 8
2.1 安全库区的应用原理 .............. 8
2.2 如何启动安全库区保护 ........... 9
2.3 如何解除安全库区保护 .......... 10
2.4 编排及执行安全库区的程序 .... 10
2.4.1 不可将中断向量表设置为安全库区 ... 11
2.4.2 安全库区代码与用户区代码的关联性. 12
3 安全库区范例程序 .................... 14
3.1 范例需求 ............................... 14
3.1.1 硬件需求 ............................ 14
3.1.2 软件需求 ............................ 14
3.2 范例概述 ................................ 14
3.3 安全库区保护的代码:FIR 低通滤波器 ....... 15
3.4 Project_L0:方案商范例 ...........16
3.4.1 产生只执行(Execute-only)代码 ....... 16
3.4.2 编排安全库区的地址 ............. 18
3.4.3 启用安全库区保护 ................. 21
3.4.4 Project_L0 执行流程 .............. 23
3.4.5 产生头文件及符号定义文件 .... 25
3.5 Project_L1:终端用户范例 ........ 26
3.5.1 建立用户的应用项目 .............. 27
3.5.2 在项目中加入符号定义文件 .... 27
3.5.3 调用SLIB 保护区的函数 .......... 29
3.5.4 Project_L1 执行流程 ............... 29
3.5.5 调试模式下的SLIB 保护 .......... 30
4 方案商和终端用户代码整合及下载操作流程 ....... 34
4.1 方案商和终端用户代码分别烧录 ......... 34
4.2 方案商和终端用户代码合并烧录 ......... 36
5 版本历史 ............................................. 39
1 概述
目前越来越多的微控器(MCU)应用需要使用到复杂的算法及中间件解决方案(middleware solution),因此,如何保护软件方案商开发出来的核心算法等知识产权代码(IP-Code),便成为微控制器应用中
一项很重要的课题。因为这一重要的需求,AT32F413系列提供了安全库区(SLIB)的功能,以防止重要的IP-Code被终端用户的程序做修改或读取,进而达到保护的目的。
本文档将详细阐述AT32F413系列安全库区的应用原理和软件使用方法。
2 应用原理
2.1 安全库区的应用原理
设定以密码保护主闪存中指定范围的程序区(即安全库区), 软件方案商可将核心算 法存放到此区域, 以达到保护的功能, 其余空白程序区可以提供给终端商客户进行二次开发。
安全库区划分为指令安全库区(SLIB_CODE)及数据安全库区(SLIB_DATA), 并可选 择部分或是整个安全库区存放指令, 但不支持整个安全库区存放数据。
指令安全库区(SLIB_CODE)内的程序代码仅能被MCU透过I-Code总线抓取指令(仅 能被执行), 不能透过D-Code总线以读取数据的方式读取(包含ISP/ICP调适模式以及从内部RAM启动的程序), 以读取数据的方式去访问SLIB_CODE时, 读到的数值 全都是0xFF。
数据安全库区(SLIB_DATA)的数据仅能透过D-Code总线读取, 不能写入。
安全库区的程序代码及数据, 除非输入正确的密码, 否则无法被擦除。在密码不正 确时, 对安全库区执行写入或擦除, 将会在FLASH_STS寄存器的WRPRTFLR位置
"1"提出警告。
终端用户执行主闪存的整片擦除时, 安全库区的程序代码及数据不会被擦除。
当安全库区的保护功能被启动后, 可以透过在SLIB_PSW寄存器写入先前设置的密 码来解除保护功能。解除安全库区的保护时,芯片将会执行主闪存的整片擦除(包含
安全库区的内容)。因此即使软件方案商设置的密码被泄漏, 也不会有程序代码外泄 的疑虑。
下图是包含安全库区的主闪存区映射示意图,安全库区的程序代码可以很容易地被终端用户调用并执行, 但不能直接被读取, 因而达到保护的功能。
图1. 带有安全库区的主闪存区映射
安全库区的范围大小是以页(Page)为单位做设定, 每一页的大小依不同型号而不同。表1是AT32F413系列各型号的主闪存大小、每页大小及可设置范围。
表1. AT32F413 各型号闪存大小总表
2.2 如何启动安全库区保护
默认状态下, 安全库区设定寄存器始终是不可读且被写保护。要想对安全库区设定寄存器进行写操作, 首先要对安全库区设定寄存器解锁, 对SLIB_KEYR寄存器写入
0xA35F6D24值, 通过查看SLIB_PSW_STS位SLIB_UNLOCK确认解锁成功, 随后便允许对安全库区设定寄存器写入设定值。
启动主闪存安全库区的步骤如下:
检查FLASH_STS寄存器的BSY位, 以确认没有其他正在进行的编程操作;
对SLIB_KEYR寄存器写入0xA35F6D24, 以进行安全库区解锁;
检查SLIB_PSW_STS寄存器的SLIB_UNLOCK位, 以确认解锁成功;
在SLIB_SET_RANGE寄存器设定要保护的区域, 包含指令区与数据区的地址;
等待BSY位变为‘0’;
在SLIB_SET_PSW寄存器设定安全区域密码;
等待BSY位变为‘0’;
烧录将存入安全库区的代码;
进行系统复位, 重装载安全库区设定字;
读出SLIB_CDR0/CDR1寄存器用于判断安全库区设定结果。
注意事项:
只可在主闪存中设置安全库区, 并且安全库区只能设置在主闪存中的前
63KB(64/128KB型号)或者62KB(256KB型号)范围内, 实际可设置范围参见表1;
安全库区代码必须以页为单位进行烧录, 且起始地址必须与主闪存地址对齐;
中断向量表是数据型态且通常会被放置在闪存的第一页(页0)内, 请勿将闪存的第一
页设定为安全库区;
要被安全库区保护的程序代码, 不可放置在闪存的前4KB内;
关于安全库区设定寄存器的详细说明, 请参阅AT32F413系列技术手册。启动安全库区的程序可参考安全库区应用范例Project_L0中位于main.c中的SLIB_Enable()函数。亦可使用雅特力的ICP或ISP刻录工具做设定, 后面章节将会有详细的说明。
2.3 如何解除安全库区保护
当安全库区的保护功能被启动后, 可以透过在SLIB_PSW寄存器写入先前设置的密码来解除保护功能。解除安全库区的保护时, 芯片将会执行主闪存的整片擦除(包含安全库
区的内容)。
解除主闪存安全库区的步骤如下:
检查FLASH_STS寄存器的BSY位, 以确认没有其他正在进行的编程操作;
在SLIB_PSW寄存器写入先前设置的安全区域密码;
进行系统复位, 重装载安全库区设定字;
读出SLIB_CDR0寄存器用于判断安全库区设定结果。
2.4 编排及执行安全库区的程序
如前面章节所提到,在指令安全库区(SLIB_Code)内的的程序代码可以被MCU经由ICode总线抓取, 但不能经由D-Code总线以读取数据的方式去读出, 这样的保护是全面
性的, 也就是说在指令安全库区之内的程序代码, 也不能读取同样被放置在指令安全库区之内的数据, 例如C程序代码常被编译成的文字池(l i teral pool )、分支表(branch
table)或常数(constant)等之类当指令被执行时会经由D-Code总线去读取的数据。这代表指令安全库区之内只能放置指令, 不能放置任何数据。因此用户在编排要放置在
指令安全库区之内的程序代码时, 必须配置编译程序(compiler)的设定去产生只执行(execute-only)的代码以避免上述那些型态的数据产生。
图2及图3是一般常见的文字池跟分支表的例子:
swi tch()是C程序中常用的跳转指令, 此例子中的tmp变量是去读取RCC_CFG寄存器,图2可看到编译出来的汇编代码(ass embl y cod e) “LDR R5, [PC, #288 ]”, 会用程序计数
器(program counter, PC)间接寻址的方式去取得RCC_CFG寄存器的地址, 而RCC_CFG的地址会被以常数的方式存放在邻近的指令区(也在指令安全库区之内), 因此执行swi tch()指令时就会发生数据的读取。如果指令安全库区内有这类的程序代码,在执行的时候就会产生错误。
第三章的范例程序将会说明如何设定编译程序的配置来避免这样的问题。
图2. 文字池例子(1)
图3. 文字池例子(2)
2.4.1 不可将中断向量表设置为安全库区
中断向量表包含每个中断处理程序的入口点地址, 由MCU通过D-Code总线读取。通常, 中断向量表位于主闪存第一页(page 0)的起始地址0x08000000, 因此在设置指令安全库区时, 必须遵守以下的规则:
不可将主闪存的第一页设置为安全库区;
要被安全库区保护的程序代码, 不可放置在闪存的第一页内。
2.4.2 安全库区代码与用户区代码的关联性
受安全库区保护的程序代码(IP-code)可以从位于用户代码区(安全库区之外的区域)的函数库中调用函数。在这种情形下, IP-Code将会包含这些函数的地址, 允许PC( 程序计
数器) 在执行IP-Code时跳转到这些函数。一旦安全库区被启动,这些函数的地址就不能被改变, 此时, 这些位于用户代码区的函数的地址就必须固定下来, 否则PC将跳转
到错误的地址而无法正常工作。因此在设置安全库区的时候, 应该将所有与IP-Code相关联的函数都一起编排到安全库区之内以避免此情况发生。下图显示出一个被保护的函
数Function_A()调用到用户区内的函数Function_B()的例子。
图4. 安全库区的函数调用用户区函数的例子
此外, 另一个最常见的情形就是使用到C语言的标准函式库, 例如memset()及memcpy()这类函数。如果IP-Code跟用户区代码都有调用到这类函数, 就会有上述问题的困扰。解决的方法就是避免在IP-Code内使用C的标准函式库, 若非要使用, 就必须将用到的函数改写为其他名称, 以下是一个范例, 在IP-code 中写一个my_memset()函数取代原先的memset()。
图5. 自定义函数范例
3 安全库区范例程序
本章节将详述完成此范例程序所需的每一个步骤。BSP中准备了一个安全库区的使用范例,路径为:
AT32F4xx_StdPeriph_Lib_V1.x.x\Utilities\AT32F413_SLIB_Demo