Skip to content

Commit d652da5

Browse files
duda-patrykfabiobaltieri
authored andcommitted
drivers: flash: Introduce readout protection support for STM32F4
This patch adds flash readout protection support for STM32F4 devices family. These devices can enable protection on entire flash content. Readout protection functionality was exposed as vendor extended operation. To change readout protection state, caller should provide a structure which describes desired RDP state. Enabling readout protection permanently or disabling readout protection (changing from level 1 to level 0) is guarded by CONFIG_FLASH_STM32_READOUT_PROTECTION_PERMANENT_ALLOW and CONFIG_FLASH_STM32_READOUT_PROTECTION_DISABLE_ALLOW respectively. Signed-off-by: Patryk Duda <[email protected]>
1 parent b6078cc commit d652da5

File tree

6 files changed

+220
-0
lines changed

6 files changed

+220
-0
lines changed

drivers/flash/Kconfig.stm32

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,28 @@ config FLASH_STM32_WRITE_PROTECT_DISABLE_PREVENTION
3737
If enabled, all requests to disable flash write protection will be
3838
blocked.
3939

40+
config FLASH_STM32_READOUT_PROTECTION
41+
bool "Extended operation for flash readout protection control"
42+
depends on SOC_SERIES_STM32F4X
43+
default n
44+
help
45+
Enables flash extended operation for enabling/disabling flash readout
46+
protection.
47+
48+
config FLASH_STM32_READOUT_PROTECTION_DISABLE_ALLOW
49+
bool "Allow disabling readout protection"
50+
depends on FLASH_STM32_READOUT_PROTECTION
51+
default n
52+
help
53+
With this option enabled it will be possible to disable readout
54+
protection. On STM32 devices it will trigger flash mass erase!
55+
56+
config FLASH_STM32_READOUT_PROTECTION_PERMANENT_ALLOW
57+
bool "Allow enabling readout protection permanently"
58+
depends on FLASH_STM32_READOUT_PROTECTION
59+
default n
60+
help
61+
With this option enabled it will be possible to enable readout
62+
protection permanently.
63+
4064
endif # SOC_FLASH_STM32

drivers/flash/flash_stm32.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,11 @@ static int flash_stm32_ex_op(const struct device *dev, uint16_t code,
398398
rv = flash_stm32_ex_op_sector_wp(dev, in, out);
399399
break;
400400
#endif /* CONFIG_FLASH_STM32_WRITE_PROTECT */
401+
#if defined(CONFIG_FLASH_STM32_READOUT_PROTECTION)
402+
case FLASH_STM32_EX_OP_RDP:
403+
rv = flash_stm32_ex_op_rdp(dev, in, out);
404+
break;
405+
#endif /* CONFIG_FLASH_STM32_READOUT_PROTECTION */
401406
}
402407

403408
flash_stm32_sem_give(dev);

drivers/flash/flash_stm32.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,9 @@ struct flash_stm32_priv {
225225
FLASH_STM32_SR_RDERR | \
226226
FLASH_STM32_SR_PGPERR)
227227

228+
#define FLASH_STM32_RDP0 0xAA
229+
#define FLASH_STM32_RDP1 0x55
230+
#define FLASH_STM32_RDP2 0xCC
228231

229232
#ifdef CONFIG_FLASH_PAGE_LAYOUT
230233
static inline bool flash_stm32_range_exists(const struct device *dev,
@@ -271,11 +274,23 @@ int flash_stm32_update_wp_sectors(const struct device *dev,
271274
int flash_stm32_get_wp_sectors(const struct device *dev,
272275
uint32_t *protected_sectors);
273276
#endif
277+
#if defined(CONFIG_FLASH_STM32_READOUT_PROTECTION)
278+
279+
int flash_stm32_update_rdp(const struct device *dev, bool enable,
280+
bool permanent);
281+
282+
int flash_stm32_get_rdp(const struct device *dev, bool *enabled,
283+
bool *permanent);
284+
#endif
274285

275286
/* Flash extended operations */
276287
#if defined(CONFIG_FLASH_STM32_WRITE_PROTECT)
277288
int flash_stm32_ex_op_sector_wp(const struct device *dev, const uintptr_t in,
278289
void *out);
279290
#endif
291+
#if defined(CONFIG_FLASH_STM32_READOUT_PROTECTION)
292+
int flash_stm32_ex_op_rdp(const struct device *dev, const uintptr_t in,
293+
void *out);
294+
#endif
280295

281296
#endif /* ZEPHYR_DRIVERS_FLASH_FLASH_STM32_H_ */

drivers/flash/flash_stm32_ex_op.c

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,3 +83,60 @@ int flash_stm32_ex_op_sector_wp(const struct device *dev, const uintptr_t in,
8383
return rc;
8484
}
8585
#endif /* CONFIG_FLASH_STM32_WRITE_PROTECT */
86+
87+
#if defined(CONFIG_FLASH_STM32_READOUT_PROTECTION)
88+
int flash_stm32_ex_op_rdp(const struct device *dev, const uintptr_t in,
89+
void *out)
90+
{
91+
const struct flash_stm32_ex_op_rdp *request =
92+
(const struct flash_stm32_ex_op_rdp *)in;
93+
struct flash_stm32_ex_op_rdp *result =
94+
(struct flash_stm32_ex_op_rdp *)out;
95+
96+
#ifdef CONFIG_USERSPACE
97+
struct flash_stm32_ex_op_rdp copy;
98+
bool syscall_trap = z_syscall_trap();
99+
#endif
100+
int rc = 0, rc2 = 0;
101+
102+
if (request != NULL) {
103+
#ifdef CONFIG_USERSPACE
104+
if (syscall_trap) {
105+
Z_OOPS(z_user_from_copy(&copy, request, sizeof(copy)));
106+
request = &copy;
107+
}
108+
#endif
109+
rc = flash_stm32_option_bytes_lock(dev, false);
110+
if (rc == 0) {
111+
rc = flash_stm32_update_rdp(dev, request->enable,
112+
request->permanent);
113+
}
114+
115+
rc2 = flash_stm32_option_bytes_lock(dev, true);
116+
if (!rc) {
117+
rc = rc2;
118+
}
119+
}
120+
121+
if (result != NULL) {
122+
#ifdef CONFIG_USERSPACE
123+
if (syscall_trap) {
124+
result = &copy;
125+
}
126+
#endif
127+
rc2 = flash_stm32_get_rdp(dev, &result->enable,
128+
&result->permanent);
129+
if (!rc) {
130+
rc = rc2;
131+
}
132+
133+
#ifdef CONFIG_USERSPACE
134+
if (syscall_trap) {
135+
Z_OOPS(z_user_to_copy(out, result, sizeof(copy)));
136+
}
137+
#endif
138+
}
139+
140+
return rc;
141+
}
142+
#endif /* CONFIG_FLASH_STM32_READOUT_PROTECTION */

drivers/flash/flash_stm32f4x.c

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717

1818
#include "flash_stm32.h"
1919

20+
LOG_MODULE_REGISTER(flash_stm32f4x, CONFIG_FLASH_LOG_LEVEL);
21+
2022
bool flash_stm32_valid_range(const struct device *dev, off_t offset,
2123
uint32_t len,
2224
bool write)
@@ -270,6 +272,108 @@ int flash_stm32_get_wp_sectors(const struct device *dev,
270272
}
271273
#endif /* CONFIG_FLASH_STM32_WRITE_PROTECT */
272274

275+
#if defined(CONFIG_FLASH_STM32_READOUT_PROTECTION)
276+
int flash_stm32_update_rdp(const struct device *dev, bool enable,
277+
bool permanent)
278+
{
279+
FLASH_TypeDef *regs = FLASH_STM32_REGS(dev);
280+
uint8_t current_level, target_level;
281+
282+
current_level =
283+
(regs->OPTCR & FLASH_OPTCR_RDP_Msk) >> FLASH_OPTCR_RDP_Pos;
284+
target_level = current_level;
285+
286+
/*
287+
* 0xAA = RDP level 0 (no protection)
288+
* 0xCC = RDP level 2 (permanent protection)
289+
* others = RDP level 1 (protection active)
290+
*/
291+
switch (current_level) {
292+
case FLASH_STM32_RDP2:
293+
if (!enable || !permanent) {
294+
__ASSERT(false, "RDP level 2 is permanent and can't be "
295+
"changed!");
296+
return -ENOTSUP;
297+
}
298+
break;
299+
case FLASH_STM32_RDP0:
300+
if (enable) {
301+
target_level = FLASH_STM32_RDP1;
302+
if (permanent) {
303+
#if defined(CONFIG_FLASH_STM32_READOUT_PROTECTION_PERMANENT_ALLOW)
304+
target_level = FLASH_STM32_RDP2;
305+
#else
306+
__ASSERT(false,
307+
"Permanent readout protection (RDP "
308+
"level 0 -> 2) not allowed");
309+
return -ENOTSUP;
310+
#endif
311+
}
312+
}
313+
break;
314+
default: /* FLASH_STM32_RDP1 */
315+
if (enable && permanent) {
316+
#if defined(CONFIG_FLASH_STM32_READOUT_PROTECTION_PERMANENT_ALLOW)
317+
target_level = FLASH_STM32_RDP2;
318+
#else
319+
__ASSERT(false, "Permanent readout protection (RDP "
320+
"level 1 -> 2) not allowed");
321+
return -ENOTSUP;
322+
#endif
323+
}
324+
if (!enable) {
325+
#if defined(CONFIG_FLASH_STM32_READOUT_PROTECTION_DISABLE_ALLOW)
326+
target_level = FLASH_STM32_RDP0;
327+
#else
328+
__ASSERT(false, "Disabling readout protection (RDP "
329+
"level 1 -> 0) not allowed");
330+
return -EACCES;
331+
#endif
332+
}
333+
}
334+
335+
/* Update RDP level if needed */
336+
if (current_level != target_level) {
337+
LOG_INF("RDP changed from 0x%02x to 0x%02x", current_level,
338+
target_level);
339+
340+
write_optb(dev, FLASH_OPTCR_RDP_Msk,
341+
(uint32_t)target_level << FLASH_OPTCR_RDP_Pos);
342+
}
343+
return 0;
344+
}
345+
346+
int flash_stm32_get_rdp(const struct device *dev, bool *enabled,
347+
bool *permanent)
348+
{
349+
FLASH_TypeDef *regs = FLASH_STM32_REGS(dev);
350+
uint8_t current_level;
351+
352+
current_level =
353+
(regs->OPTCR & FLASH_OPTCR_RDP_Msk) >> FLASH_OPTCR_RDP_Pos;
354+
355+
/*
356+
* 0xAA = RDP level 0 (no protection)
357+
* 0xCC = RDP level 2 (permanent protection)
358+
* others = RDP level 1 (protection active)
359+
*/
360+
switch (current_level) {
361+
case FLASH_STM32_RDP2:
362+
*enabled = true;
363+
*permanent = true;
364+
break;
365+
case FLASH_STM32_RDP0:
366+
*enabled = false;
367+
*permanent = false;
368+
break;
369+
default: /* FLASH_STM32_RDP1 */
370+
*enabled = true;
371+
*permanent = false;
372+
}
373+
return 0;
374+
}
375+
#endif /* CONFIG_FLASH_STM32_READOUT_PROTECTION */
376+
273377
/*
274378
* Different SoC flash layouts are specified in across various
275379
* reference manuals, but the flash layout for a given number of

include/zephyr/drivers/flash/stm32_flash_api_extensions.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,14 @@ enum stm32_ex_ops {
2121
* Output can be NULL if not needed.
2222
*/
2323
FLASH_STM32_EX_OP_SECTOR_WP = FLASH_EX_OP_VENDOR_BASE,
24+
/*
25+
* STM32 sector readout protection control.
26+
*
27+
* As an input this operation takes structure with information about
28+
* desired RDP state. As an output the status after applying changes
29+
* is returned.
30+
*/
31+
FLASH_STM32_EX_OP_RDP,
2432
};
2533

2634
#if defined(CONFIG_FLASH_STM32_WRITE_PROTECT)
@@ -33,3 +41,10 @@ struct flash_stm32_ex_op_sector_wp_out {
3341
uint32_t protected_mask;
3442
};
3543
#endif /* CONFIG_FLASH_STM32_WRITE_PROTECT */
44+
45+
#if defined(CONFIG_FLASH_STM32_READOUT_PROTECTION)
46+
struct flash_stm32_ex_op_rdp {
47+
bool enable;
48+
bool permanent;
49+
};
50+
#endif /* CONFIG_FLASH_STM32_READOUT_PROTECTION */

0 commit comments

Comments
 (0)