软件供应商们在致力于开发属于自己的知识产权的软件产品,尤其是那些中间件产品的同时,如何保护这些知识产权[IP]实际上也是他们非常关心和重视的问题。基于各类微处理器的嵌入式产品对IP保护的要求也日益明显和迫切。
为了满足对产品IP保护的需求,STM32的各系列MCU都提供芯片读保护写保护。除此之外,目前STM32家族10个产品线中,除了STM32F1等个别早期产品线外,还增加了专有代码读保护功能,即Proprietary Code Read Out Protection (PCROP)。
• Read Protection(RDP): 对整个芯片实施读出保护;
• Write Protection: 防止意外的对存储器的擦、写操作;
• PCROP: 针对指定扇区进行读写保护;
PCROP为Proprietarycode readout protection 的缩写,是一个专有代码读出保护的功能。与RDP 对整片Flash读保护不同的是,它只是针对Flash 的某些特定区域进行代码的读写保护。它可以被用来保护一些IP代码,方便进行二次开发。ST公司的多个STM32产品系列,比如STM32L1、STM32F4、STM32L4、STM32F7、STM32H7等都支持PCROP功能。
受PCROP保护的IP代码可以随意地被用户应用程序调用运行,同时又防止外界对IP代码的直接读写访问。一咋看这句话理解起来可能有点别扭,稍微琢磨下应可反应过来。相信不少软件工程师在开发中有时会用到第三方库代码,有些库代码是编译过的lib库,看不到source code,但你能使用调用它,有点类似。
写保护和PRROP保护都可以针对指定的扇区配置,但是在同一存储器内要么针对扇区实施写保护,要么针对扇区进行PCROP保护。不可以一部分扇区配置写保护,另一部分扇区配置PCROP保护。
PCROP区的代码也可以调用PCROP区外的处于固定地址的函数。
受PCROP保护的区域是无法使用D-Code 总线进行读访问的,所以在这片区域中只允许执行指令代码(通过I-Code 总线取指令),数据读取是被禁止的。因此,受保护的IP代码不能访问存储于同一块区域内的关联数据,比如文字池(literal pools)、分支表(branch tables)以及在执行过程中需要通过D-code总线进行读取的常量数据。
换言之,受PCROP 保护的代码只能是只执行的指令代码,而不包含任何数据。因此,我们在编译受PCROP保护的IP代码时,必须对其进行相应配置,以避免在PRROP区域生成文字池、常量数据等。
我们知道STM32的中断向量表里都是些常量数据,所以包含中断向量表的扇区不可进行PCROP。一般来讲向量表放在第一个扇区,所以该扇区不可进行PCROP。
不同的编译工具链有其自己的配置方式去阻止编译器生成文字池和分支表。我们来看一下基于MDKKeil中和IAR 开发环境的设置操作。
Keil:使用Execute-only命令
1) 右击项目中的IP代码文件组(比如ST 官方应用笔记AN4701例子中的FIR-Filter),选择“Options for Group‘FIR-Filter’”
在对话框中选择“C/C++”页面,选中“Execute-onlycode”,点“OK”。
2) 另外,还需修改Keilscatter file(.sct文件),设置IP 代码为只可执行代码:
LR_PCROP 0x08008000 0x00004000 {
ER_PCROP 0x08008000 0x00004000 { ; load address = execution address
arm_fir_f32.o (+XO)
arm_fir_init_f32.o (+XO)
FIR_Filter.o (+XO)
}
}
IAR:代码内存中不进行数据读取
对于IAR,必须使用选项“No data reads in code memory”来防止编译器对代码扇区生成任何数据访问。要激活此选项,请右键单击包含IP-Code源文件的文件组“FIR-Filter”,然后选择Options。
然后,在以下窗口中,选择选项“No data reads in code memory”,如图所示。
IAR ICF文件
要使用IAR将IP-Code放在Sector 2中,请打开ICF文件并添加新的加载区域,如下所示:
define symbol __ICFEDIT_region_PCROP_start__ = 0x08008000;
define symbol __ICFEDIT_region_PCROP_end__ = 0x0800BFFF;
define region PCROP_region = mem:[from __ICFEDIT_region_PCROP_start__ to __ICFEDIT_region_PCROP_end__];
place in PCROP_region { ro object arm_fir_f32.o,
ro object arm_fir_init_f32.o,
ro object FIR_Filter.o};
最后以一个基于STM32F4的PCROP实际应用案例分享结尾。
某客户使用了STM32F446ZET6,开启PCROP 的功能,对他们的算法代码进行保护。在使用过程中,他发现位于PCROP 区的函数无法被用户程序调用。
经了解,客户使用Keil MDK 进行项目的开发。检查客户的代码,看是否在项目中的IP代码的Options 中使能了“ExecuteonlyCode”选项,发现并没有将之使能。于是将此选项使能后,并编辑.sct 文件,再编译,运行代码。问题解决。
原因就在于客户未对IP 代码部分进行相应的配置处理,从而导致编译器未在PCROP区域避免生成文字池和分支表等数据。故而在调用PCROP内部的函数时触发了D-code 总线去访问PCROP 区域,导致错误发生。
对于PCROP 功能的详细使用说明,请参考应用笔记AN4701《Proprietary code read-out protectionon microcontrollers of theSTM32F4 series》及其相应的参考代码X-CUBE-PCROP.zip。
文章出处: 茶话MCU