一.前言
: d. v" g4 E5 T; OProprietary Code Read Out Protection (PCROP) ----- 专有代码读取保护
4 D; u/ n- _' b+ l/ {6 _$ [现在产品开发过程中,二次开发将会越来越多,设计公司开发出自己产品后交给终端客户进行二次功能或补充开发,简称二次开发,设计公司某些程序代码不希望公开给终端客户,但同时又希望部分函数功能可以给终端客户使用,这时就需要有一种专有代码保护机制供客户使用,STM32F4xx 芯片中的PCROP 可以解决类似问题。
" V* T9 M6 A$ _7 g V+ g( }3 U' W6 y. D3 E3 N r
二.PCROP 简要描述
4 S' h( ?) e/ K v0 A+ k; u$ |PCROP 功能在 STM32F42xxx 和 STM32F43xxx 芯片中包含,当使用 PCROP 时,用户扇区(0--23)Flash 能够阻止 D-Bus 的读取指令;保护功能选择通过 FLASH_OPTCR 寄存器的 SPRMOD 选择位进行选择:
: ~( e# U8 n9 T+ f• SPRMOD = 0: nWRPi 用于控制用户扇区写保护
5 Z8 V" ]4 E9 r2 p• SPRMOD = 1: nWRPi 用于控制 PCROP 读写保护" y7 M8 O# x. W# J' J) D
当 PCROP 功能使能时:+ D5 j8 m/ a: {0 _* \( A% ]
任何通过 D-Buss 的读取动作将会有 RDERR 错误标志" j" o; B7 w5 {
任何对 PCROP 保护的扇区的擦除/写入操作将会有 WRPERR 错误标志* c- ]0 W. G5 I) B/ _
PCROP 保护等级设定如下:) x! D. `( U# n! R& ^
- a+ M& T C0 M7 q$ }/ X! I) T
5 l8 b6 o! s, j9 W& a$ A, N5 U9 U3 {) U z6 ?2 C* J9 V
三. 如何使用 PCROP 功能
0 {9 B; U8 n, j( f1. 需要使用 6.50 以上版本的 EWARM(IAR),使能 C/C++ Complier --> Code--> No data reads in code memory ;
& E1 y3 D* e4 F' ?$ _5 H; l4 z' a7 {' ^# s4 O8 T! ~) U
7 K \. x1 f( y& u
& r9 R4 e. Z7 K2. 修改 stm32f4xx_flash.icf 文件,定义 PCROP 保护的地址空间;
0 D& r9 ^; ]- e- _ n9 t8 ?0 j0 A! t
% X1 V6 G/ |7 r8 D; l
5 S* X, B4 R8 a, B" K 本文使用 STM32F429NIH6 芯片的 0x08008000---0x0800BFFF(Sector 2)作为 PCROP 保护区域,stm32f4xx_flash.icf 修改如下:: d4 ~7 a8 ^8 D! [4 g) s: Z
- /*###ICF### Section handled by ICF editor, don't touch! ****/
. w& ^, F8 F& V - /*-Editor annotation file-*/
5 _0 V7 Z* b! J$ W - /* IcfEditorFile="$TOOLKIT_DIR$\config\ide\IcfEditor\cortex_v1_0.xml" */
; R% U; G7 |5 C$ `* r- Z - /*-Specials-*/
! m; T( G- f# ]' t9 T% v3 r - define symbol __ICFEDIT_intvec_start__ = 0x08000000;
) x2 c4 |4 T, Z& g1 P - /*-Memory Regions-*/
) Y% Q0 A& S( x# O - define symbol __ICFEDIT_region_ROM_start__ = 0x08000000;8 @' S" g/ O0 e: {) t
- define symbol __ICFEDIT_region_ROM_end__ = 0x08003FFF;
7 C# w& A( v, @8 H2 D - define symbol __ICFEDIT_region_CODE_start__ = 0x08008000;
& I7 [- I+ i* F6 ?8 ]4 W - define symbol __ICFEDIT_region_CODE_end__ = 0x0800BFFF;# B, @5 b: S0 Z
. X& l* k& X. i" |3 z- define symbol __ICFEDIT_region_RAM_start__ = 0x20000000;$ H p: V) w# ]
- define symbol __ICFEDIT_region_RAM_end__ = 0x2002FFFF;
; n, @9 ^' a7 s - define symbol __ICFEDIT_region_CCMRAM_start__ = 0x10000000;# Z* U, m( p/ r
- define symbol __ICFEDIT_region_CCMRAM_end__ = 0x1000FFFF;
( f4 [- x4 a+ C# ?/ _ - /*-Sizes-*/
" n3 y) A3 A8 g! W - define symbol __ICFEDIT_size_cstack__ = 0x400;
- t& g" g* V1 e4 L - define symbol __ICFEDIT_size_heap__ = 0x200;% D) Y% m1 t6 T7 {
- /**** End of ICF editor section. ###ICF###*/
" q. n L# S& R% X# Q) v3 |8 V - define memory mem with size = 4G;; ^. w% ? M0 R" _0 e: f
- define region ROM_region = mem:[from __ICFEDIT_region_ROM_start__ to& r- _/ k2 k- D. U
- __ICFEDIT_region_ROM_end__];1 Z/ X5 k' d3 e) x2 F( P
- define region CODE_region = mem:[from __ICFEDIT_region_CODE_start__ to
( C. p$ A5 W$ _7 x - __ICFEDIT_region_CODE_end__];; I/ S9 R+ v/ u
- define region RAM_region = mem:[from __ICFEDIT_region_RAM_start__ to
0 \# A# {9 t4 l( F4 P( w4 k) ~ - __ICFEDIT_region_RAM_end__];
1 O, A, Y# e5 M {+ ], ~ - define region CCMRAM_region = mem:[from __ICFEDIT_region_CCMRAM_start__ to
- {* W& i& w- }3 K! k - __ICFEDIT_region_CCMRAM_end__];, |; z4 [$ a" t6 f* Q/ ]4 r/ b
- define region TabCode = [from 0x08004000 to 0x08007FFF];
! `! i& x! ~% l B, v. e - place in TabCode { ro section .tab, };
. l4 t* A! K% i( q0 p5 C" g$ W* ` - define block CSTACK with alignment = 8, size = __ICFEDIT_size_cstack__ { };
: |2 ?% p2 e. f' {, p8 j - define block HEAP with alignment = 8, size = __ICFEDIT_size_heap__ { };8 o% \ I9 F E2 t
- initialize by copy { readwrite };
, G5 m5 S7 y5 a# S- m - do not initialize { section .noinit };9 P5 [5 v' Y$ P
- place at address mem:__ICFEDIT_intvec_start__ { readonly section .intvec };
8 H. }& _# @* J - place in CODE_region {section .CODE_Flash};
' j/ n7 R- e2 q8 Y" v: G - place in ROM_region { readonly };
$ k& H. g) ^- m3 V, y, D - place in RAM_region { readwrite,6 {% J. P" L0 D7 J
- block CSTACK, block HEAP };
复制代码 ' s: |) e1 r6 u: W6 T A
3. 修改 startup file (.s)文件 Reset_Handler 中 LDR 修改为 BLX:: b0 W& k+ s+ l/ @( n) m* [
- Reset_Handler
" H! O" F4 r5 ]# C& c - LDR R0, =SystemInit
/ ]& K* C% F* Y" P# P5 a - BLX R02 y5 w2 L& t: a
- LDR R0, =__iar_program_start
8 S$ K+ U& Z& ]. Y - BX R0
# k3 r; d* l& G' \ - 修改为:
* _& R7 V8 a* x0 W @: ` - Reset_Handler, ^! W' i7 L _/ D/ p. s
- BLX SystemInit
+ f! q$ _9 P7 e7 \. C - BLX __iar_program_start2 m0 H* l% C5 h( {
复制代码
2 A, a, u3 n0 ~, D' V) j) t4. 定义程序到 PCROP 保护区域中:
) o9 C4 x: V5 g }, S 本文实例文件 Sector_Test.c 中定义 Light_Togger()函数定义在 0x08008000-0x0800BFFF 区域:
u; q% ^- d' E) `$ i- #include "stm32f4xx.h"
2 h0 n: ]& I3 N1 I' \' K, n - #pragma location = ".CODE_Flash"3 n" h7 i' c: f3 h
- void Light_Toggle(void)3 u! T$ A- y0 b) `2 f7 S
- {7 l0 X3 ~/ L" W$ l3 C
- GPIOG->BSRRH = GPIO_Pin_6 | GPIO_Pin_7;1 y- V/ o4 f) P, r7 v
- }
复制代码
4 Y% ]2 P" h. H$ [) y8 U5. 使用 STVP 对 OPTION BYTE 进行编程,使能 PCROP,并且选择保护区域:
: L( e6 v% l. s& T8 Q5 u" ?$ ~
/ |1 K! p6 X2 d4 V
( c/ u3 L$ B, D9 x3 }
1 F; V8 K2 z4 I' S6 K+ S1 U, ?此时可以读取下 0x08008000---0x0800BFFF 区域的数据,可以看到改 PCROP 空间数据不可读,但程序依然可以调用该区域函数---- Light_Togger()
. }' U% e4 A, {; `. |
8 e1 e+ v9 p9 @% w. r, V9 r
; l3 x, g5 W( E$ W( E
3 X- r* _* q( |四.本文所用测试代码说明以及代码- [4 z! E, ^5 X$ U4 d6 `
6 J8 i3 K) t, h7 Y. S# P
Main 函数作为客户程序代码,而需要调用的函数 Light_Togger()位于 PCROP 保护区域(0x08008000---0x0800BFFF),实现 GPIOG_6/GPIOG_7 端口的 Toggle;
. c$ k& ]4 {& gMain.c 文件如下:( P9 e6 Q1 l: z+ C
- /* Includes ------------------------------------------------------------------*/3 v. x9 _9 A- l, s( d# D
- #include "main.h"
8 M# r% ~1 Q& B7 a1 j# w9 e9 x7 _ - extern void Light_Toggle(void);8 h; q7 \+ T5 S. q- L2 F
- int main(void)
2 w" x$ i- P4 k, z - {9 n* m3 k, _# \
- unsigned int i;
3 c3 `2 l" O9 F+ D - GPIO_InitTypeDef GPIO_InitStructure;( K- B: Z5 \. g* K; n- r1 y
- /* GPIOG Peripheral clock enable */4 G/ Q* m0 }+ H9 P5 h" a8 w. t" t
- RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, ENABLE);2 P+ R- O# P. ^! ^
- /* Configure PG6 and PG8 in output pushpull mode */ \; O8 S) B3 F3 {8 m
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;4 n3 T- { p. k: D7 D! z5 i
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;# w" o* \2 l6 M7 a* U# Y, _$ S
- GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
4 y% [, q; K& m9 E* o2 P$ c - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
& x! [& h/ q- J - GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
% H# C8 D- j/ F ^& S - GPIO_Init(GPIOG, &GPIO_InitStructure);
" p* H9 S6 H7 s; |& v - 0 Y: y* W' ]6 e
- while(1), x9 ^7 }& [" [: Z5 k6 s
- {: {1 i& U8 c0 \7 m
- GPIOG->BSRRL = GPIO_Pin_6 | GPIO_Pin_7;# B6 w# Y& _7 K4 y& j% O2 V
- i = 0xFFFFFF;6 H7 R/ d+ q( ]
- while(i--);
4 J. a% }5 B3 S9 f: l& N - Light_Toggle();2 h. {% J; m0 g% c# q$ H4 ^* }
& E& B. P, i/ u2 S) ^& E- i = 0xFFFFFF;- x! s- |) H! x( w4 C1 v( T, A- T
- while(i--);0 u& b6 v6 S1 b8 b
- }
& ?6 s- H6 a$ ]; v0 A - }
复制代码
$ W' F. G6 m% E9 P% kSector_Test.c 如下:
9 {' O5 j- i; Q. @- Y+ |- #include "stm32f4xx.h"
0 f+ F& g U( d6 i$ B - #pragma location = ".CODE_Flash"
: Z: a; L, u' a8 Y1 f9 W - void Light_Toggle(void)
; N. t }: ?2 U. w - {
" B7 `5 |9 G* z' N! c - GPIOG->BSRRH = GPIO_Pin_6 | GPIO_Pin_7;& A {1 i0 \- ^9 S* ~' _% k6 `
- }
复制代码
0 `* T6 X" ^8 T2 q4 L0 M' U; W: m; `+ n+ l2 ~
|