前言" _% m, x2 y4 Q: p& y w- V
STM32 PCROP 专有代码读出保护,将某个区域设置为仅允许执行,可防止代码被非法读出与修改。ST 网站提供了免费的PCROP 参考代码,但是例程中仅仅提供了用代码设置 PCROP。为方便利用 PCROP 进行知识产权保护的开发和部署,这篇文章提供了方法, 可在 RDP 级别设置为 1 或者 0 时,使用代码清除 PCROP。
' V$ Q# W- j/ N! K {: s
, X+ k: c$ z5 y0 ]+ vST 网站上的 PCROP 参考代码 G7 ]5 _7 ]2 E) J
学习使用 PCROP,可从 ST 网站下载文档以及参考代码。文档里有一步一步的详细说明。参考代码则实现了,如何设置编译开发环境去掉文字库(Literal pool),以避免受保护区域需要被读访问;参考代码也实现了如何利用代码使能 PCROP 保护以及如何导出接口符号供二次开发使用。你可以编译运行 PCROP 参考代码。一旦下载到开发板并运行后,扇区 2 会自动被设置成 PCROP 保护。你将无法再次下载
/ |" L5 O) V V5 c, C* a+ ]! N代码到该扇区,也无法读出该扇区的内容。若想通过 STLink 工具解除 PCROP 保护,则会导致整个 Flash 被擦除。5 o& t$ U4 i( f& g* Y
# W: A/ N9 d- g2 D
使用代码清除 PCROP+ @5 H" \& Y. F# T1 `7 G; w( v
在熟悉 ST 网站上的 PCROP 参考代码基础之上,我们将讨论如何使用代码清除 PCROP。# ^1 ~( C- r7 _5 U \
1. 原理
# P/ A9 T( s% {7 I0 z+ m 根据用户手册,要想清除 PCROP 保护,读保护 RDP 级别必须从 1 设置成 0。也就是说,即使当前 RDP 级别为 0,我们也要使用代码将其设置成 1。然后,同时关掉 PCROP 和将 RDP 设置成 0。这也说明,尽管是清除 PCROP 保护,我们的代码必须加入 RDP 的设置函数, 而不能仅仅修改参考代码中的 PCROP_Enable 的状态字段使其变成 PCROP_Disable。
+ f, L) f0 j( m) s( p6 r, q) C l' H
9 S$ l, f1 H) }3 n5 r' M d( ~
* \( m7 T# b6 ]% N3 r$ u* U$ f! n5 c9 q M! }, v5 n0 }
2. 材料准备& o% _' c6 ?0 W9 I$ |' ]5 H
开发板: STM32F429I-Discovery
# M/ B# r! j4 C" u. w 开发工具:STM32Cube_FW_F4_V1.15.05 x/ I8 ^% r, j- Y$ y1 V; H* i
STM32CubeExpansion_AN4701_F4_V1.0.0(从 ST 网站下载的参考代码)
) ^! Y0 v) W3 @6 |) B STM32 STLink8 f5 x! |" a: M
IAR/Keil
2 [1 k- V3 ^3 I 注:也可以选择其他支持 PCROP 的 STM32 系列并选择相应的开发板与固件库。
6 u4 N$ D, h- \# e1 V+ A3 u3. 代码5 G L+ {: P" f1 j7 A
设置 RDP 到级别 1* t+ M9 l" w. \# z4 U
该函数在 RDP 级别为 0 时,若需要清除 PCROP, 必须被使用。8 d. b! q/ C5 ?% K; e( T' l
- void RDP_Enable()0 o: \! q9 } s9 | ]
- {
2 P2 b$ c+ Z3 o0 n - HAL_FLASH_OB_Unlock();! v5 X7 V; g; e( E& J# O7 `
- /* Allow Access to Flash control registers and user Falsh */
# f+ R4 ]. U+ a3 z - HAL_FLASH_Unlock();
* t' F" e9 m: {8 ^8 {2 P3 O - HAL_FLASHEx_OBGetConfig(&OBInit);$ ?- V8 |# k* @" j5 Q- h' u+ ~4 v
- //After programming please power off and power on in order to use this board3 N% a- a! s# A) V0 a4 \
- if(OBInit.RDPLevel == OB_RDP_LEVEL_0)
& d$ }9 Y8 Q7 Q/ U/ o - {3 g' Z* Q; k5 l$ q- ^
- OBInit.OptionType = OPTIONBYTE_RDP;0 p3 v- c8 ]5 E' A3 B
- OBInit.RDPLevel = OB_RDP_LEVEL_1;
1 D* q, I3 X' h5 w! g - HAL_FLASHEx_OBProgram(&OBInit);
( t0 _( S+ E- e5 u! c
, E5 e+ ^& K8 j, B4 ]- /* Start the Option Bytes programming process */
0 h3 g, t# s- u - if (HAL_FLASH_OB_Launch() != HAL_OK)
0 t% l r5 q ~ p - {
+ ~7 f& b/ v& V; v2 N& ` - /* User can add here some code to deal with this error */) Q' \5 U% w k. `% v1 d& L6 f( r
- while (1)
I. v( k: V) s: W- y( Z$ K; L2 O - {8 w8 g/ q. H e3 D
- }
6 |; d: ]$ d% Q6 K. D+ h - }: }- |9 m9 R7 m1 X3 _/ T
- }
1 `) ]- }0 }; _% R$ @& K7 H - /* Prevent Access to option bytes sector */6 N+ i7 ?, U/ W) {7 Z
- HAL_FLASH_OB_Lock();
7 z) n$ A: \! F9 N/ U4 \ - HAL_FLASH_Lock();
5 {5 `7 }, c( a+ E; _ - }
复制代码
: e) p' f) d8 ^2 h+ B; N4 @ 设置 RDP 到级别 04 V' R% X- O# W
在清除 PCROP 保护的代码里不会直接调用这个函数。参考手册提到,PCROP 的清除必须与 RDP 从 1 到 0 同时发生,而下列 RDP_Disable 函数则是完整独立的,无法与 PCROP 的 Option bytes 同时操作。不过,这个代码的中间部分,也就是实际功能部分,将在清除 PCROP 时被重用。
+ y1 y0 b5 d. l+ J- P- r- void RDP_Disable()/ L5 O# x8 m! N" V9 c
- {+ w: j p$ M1 ]6 }
- HAL_FLASH_OB_Unlock();. w, h% C: u0 J% d
- - I3 l& n% d* I, s0 e& ^. M
- /* Allow Access to Flash control registers and user Falsh */( C, ^1 T* _ }% w5 y& r e. k
- HAL_FLASH_Unlock();
& S I q3 L0 @& I; c! `1 _ - 3 n" }3 U9 \$ k- x6 y( ?( `
- HAL_FLASHEx_OBGetConfig(&OBInit);0 j4 F1 W8 l+ x5 [3 D
- //After programming please power off and power on in order to use this board* q; A9 V0 q8 u& f. r% ~2 D! R# r
- if(OBInit.RDPLevel == OB_RDP_LEVEL_1)9 r5 o' T% f* J5 r$ f% X. ?3 w
- {
( {; E4 W' @& {/ t - OBInit.OptionType = OPTIONBYTE_RDP;# ?# h+ p/ {( M( ?
- OBInit.RDPLevel = OB_RDP_LEVEL_0;
: v. c" s- l: G2 P - HAL_FLASHEx_OBProgram(&OBInit);
P0 g: t+ j4 T( P( v8 H1 g$ Q* l0 i
+ Z4 k) o% b% o c% q0 F$ k- /* Start the Option Bytes programming process */
/ N6 U9 Z3 q% _" x - if (HAL_FLASH_OB_Launch() != HAL_OK)
l' w; i5 J5 {1 P# k/ s9 P& j3 ~ - {
- w% f: _+ W5 _) G4 s$ U - /* User can add here some code to deal with this error */, F0 L* Z2 `9 j2 G2 O
- while (1)
$ n, i* a7 m6 |. W) l' Q6 u; ~5 K! w - {
9 ?2 Z9 t: E3 A7 F - }, s8 V* q. F- L
- }
/ ]. c# ]8 d, ?. r! B - }$ g7 }: ]4 k" ]3 x' I
- /* Prevent Access to option bytes sector */+ K! V5 ]: o% e
- HAL_FLASH_OB_Lock();5 R, A) F+ i! }' K% [
- HAL_FLASH_Lock();
' E5 _8 T: ]5 a$ v - }
复制代码
0 m* f: b2 A$ V* O# E9 } 清除 PCROP
# S( N3 ?3 U. x/ Z下述代码清除 PCROP, 它基于参考代码中的 PCROP_Enable 函数改写而成。首先,它通过 RDP_Enable 将 RDP 设置成 1。注意实验中不要将 RDP 设置成为 2,否则所有的 Option bytes 将不再被允许修改。然后将 RDP 和 PCROP 都设置完毕,调用一次 HAL_FLASH_OB_Launch 达到同时将 RDP 设置成 1 并清除 PCROP 保护。
* F* w9 |- a. K! ~- N- uint32_t PCROP_Disable(void)4 T5 c# s: J5 `8 L4 v
- {1 {2 W# f- |3 k
- % j7 ]5 m( y0 {: ~1 w* i. G
- RDP_Enable();
/ S* i, R2 c; d$ d3 J* c4 F - 4 b I$ s& S: `) K: K# ]) x0 @: H
- /* Get FLASH_PCROP_SECTORS protection status */9 d Z4 @6 n) g2 E4 f2 f
- HAL_FLASHEx_AdvOBGetConfig(&pAdvOBInit); | k1 X: e2 R' I0 K% w6 y! N
- SectorsPCROPStatus = pAdvOBInit.SectorsBank1 & FLASH_PCROP_SECTORS;- H$ S( P& m% Y7 y7 n+ ^4 y2 k* j
- PCROPStatus = pAdvOBInit.SectorsBank1 & PCROP_ENABLED;/ g, f( u5 P4 W
# T4 T1 ]; t1 J, e6 ~- /* Check if sector 2 has been already PCROP-ed */' v* S! A7 Z6 N& A2 v
- if ((PCROPStatus == PCROP_ENABLED) && (SectorsPCROPStatus == FLASH_PCROP_SECTORS))+ N2 ?. l6 Z6 Q2 Z
- {
0 s" X) `; K. i' X - /* Allow Access to option bytes sector */' X# M0 f5 q" p! M( |8 w& Z- S
- HAL_FLASH_OB_Unlock();6 u; n2 R) S; J+ }2 o; ]
- /* Allow Access to Flash control registers and user Flash */
7 P L U! l3 ^, k( b! l - HAL_FLASH_Unlock();
% ?& d4 x& I* ^- w1 Y - /* Clear all nWRP bits */+ ?+ ?9 K2 u; v' C6 R: ~8 e
- pAdvOBInit.OptionType = OPTIONBYTE_PCROP;
8 }4 b9 l) ]( M) `8 T - pAdvOBInit.PCROPState = OB_PCROP_STATE_DISABLE;( B v/ f0 ^4 x) m7 I
- pAdvOBInit.Banks = FLASH_BANK_BOTH;
) j- M: n3 h8 ^4 i - pAdvOBInit.SectorsBank1 = OB_PCROP_SECTOR_All;
1 q8 X, n7 u7 _/ Q8 h6 h - pAdvOBInit.SectorsBank2 = OB_PCROP_SECTOR_All;- m% }2 C0 a) c6 n3 T7 D4 L" p
- HAL_FLASHEx_AdvOBProgram(&pAdvOBInit);* o$ Z5 Z+ W) ^4 o! m
- /* Clear PCROP protection on sector 2 by setting nWRP 2 bit */
& }( s% y- v2 f3 M7 \) s+ S - pAdvOBInit.OptionType = OPTIONBYTE_PCROP;0 p3 U9 l! @( P! C' Z: Y! p& T( D
- pAdvOBInit.PCROPState = OB_PCROP_STATE_DISABLE;* g! e$ ]% E# p! q# K1 y) u/ r
- pAdvOBInit.Banks = FLASH_BANK_1;
+ C" ^+ k+ l/ Z: ` - pAdvOBInit.SectorsBank1 = OB_PCROP_SECTOR_2;$ a5 R$ N( f( f% ?5 q
- HAL_FLASHEx_AdvOBProgram(&pAdvOBInit);0 y3 T7 F( \0 R9 d* w+ s
- : W: k& L0 C/ y2 T: ?2 J4 E$ A
- /* Disable PCROP Protection by setting SPRMOD bit */- O6 |2 P3 r- l2 i
- HAL_FLASHEx_OB_SelectPCROP();* d0 C) s! j) j* E
- /* Set RDP from 1 to 0*/
5 Q; l9 U4 X' ^ - OBInit.OptionType = OPTIONBYTE_RDP;
, w% w2 _4 l4 T7 A! j - OBInit.RDPLevel = OB_RDP_LEVEL_0;
W9 \! `) Y: ~1 C* Q% Q+ D: Q - HAL_FLASHEx_OBProgram(&OBInit);
0 I ?2 g, A) @$ H- d" i7 c- R2 ^ - /* Start the Option Bytes programming process */
+ E' @. D. E# Q' b) ?' Q! ~; ] - if (HAL_FLASH_OB_Launch() != HAL_OK)* E2 y+ E: e6 o7 H% o7 x
- {! Y( E c3 a* s% }, L
- /* Error occurred while options bytes programming */; P( q, J9 ~7 u4 O( Y' I
- return(0);/ r6 P7 a8 Y. p& w2 P
- }0 _% o- c- x. a6 k( |* J, R. I
- /* Prevent Access to option bytes sector */
' ~: }* z% }6 Q$ z- j; x - HAL_FLASH_OB_Lock();
% \ W7 x" ]* o7 E5 x$ f - /* Disable the Flash option control register access (recommended to protect5 h9 K% _% ~7 o/ F! P' X) A9 o0 Z! P
- the option Bytes against possible unwanted operations) */" h! {7 b5 H! G( s
- HAL_FLASH_Lock();
9 j' \& a3 j+ T - ( K$ I/ Q2 V7 t* }
- /* PCROP Protection successfully Enabled */
; W5 O! j& B* J3 v$ M+ L - return(1);
; [: e+ r5 R3 g- C8 b: p* c - }+ ~, L Z5 ?, N0 x! h
- }
复制代码
0 a; o& z: y( [2 D" z s& f4.运行1 B2 g( e; _/ H, [3 j. _" K# j
在主函数中,调用 PCROP_Disable 可解除 PCROP 保护。RDP_Enable 后需要关闭电源,重新启动,然后系统正常运行解除 PCROP 保护。解除保护后,可通过 STLink 确认 PCROP Option bytes 已恢复,同时也可以看到整个 Flash 内容已被擦除。
4 u( @: a7 q# E& J* N0 Z$ V5 p; d
3 }: B$ S4 Y" D8 \. R0 i4 U$ J7 d
! H( c& U1 V5 n" Y. }% q0 z' G结论; m* I: M5 U, M0 L' z
本文讨论了完全使用代码控制 PCROP 的设置与清除。它可以使用在 PCROP 代码保护的开发与部署阶段。" C: a5 K+ M, b+ U
) R' j1 ?7 @8 ?( W
) z1 T, d# n3 |0 w1 M |