Skip to content

Commit 78ce578

Browse files
duda-patrykfabiobaltieri
authored andcommitted
drivers: flash: Add ex ops for STM32 option/control register block
Introduce flash extended operations that can be used to disable access to option and control registers until reset. Disabling access to these registers improves system security, because flash content (or protection settings) can't be changed even when exploit was found. On STM32 devices, registers can be locked until reset by writing wrong key during unlock procedure. It triggers a bus fault, so during the procedure we need to ignore faults and clear bus fault pending bit. Please note that option register disabling was implemented for devices that have OPTCR register (F2, F4, F7 and H7). Implementation on other devices requires more testing, since documentation is not precise enough. Disabling control register was implemented for devices that have CR register. Signed-off-by: Patryk Duda <[email protected]>
1 parent 417368e commit 78ce578

File tree

3 files changed

+94
-0
lines changed

3 files changed

+94
-0
lines changed

drivers/flash/Kconfig.stm32

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,4 +61,13 @@ config FLASH_STM32_READOUT_PROTECTION_PERMANENT_ALLOW
6161
With this option enabled it will be possible to enable readout
6262
protection permanently.
6363

64+
config FLASH_STM32_BLOCK_REGISTERS
65+
bool "Extended operation for blocking option and control registers"
66+
default n
67+
help
68+
Enables flash extended operations that can be used to disable access
69+
to option and control registers until reset. Disabling access to these
70+
registers improves system security, because flash content (or
71+
protection settings) can't be changed even when exploit was found.
72+
6473
endif # SOC_FLASH_STM32

drivers/flash/flash_stm32.c

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,67 @@ int flash_stm32_option_bytes_lock(const struct device *dev, bool enable)
376376
return 0;
377377
}
378378

379+
#if defined(CONFIG_FLASH_STM32_BLOCK_REGISTERS)
380+
static int flash_stm32_control_register_disable(const struct device *dev)
381+
{
382+
FLASH_TypeDef *regs = FLASH_STM32_REGS(dev);
383+
384+
#if defined(FLASH_CR_LOCK) /* F0, F1, F2, F3, F4, F7, L4, G0, G4, H7, WB, WL \
385+
*/
386+
/*
387+
* Access to control register can be disabled by writing wrong key to
388+
* the key register. Option register will remain disabled until reset.
389+
* Writing wrong key causes a bus fault, so we need to set FAULTMASK to
390+
* disable faults, and clear bus fault pending bit before enabling them
391+
* again.
392+
*/
393+
regs->CR |= FLASH_CR_LOCK;
394+
395+
__set_FAULTMASK(1);
396+
regs->KEYR = 0xffffffff;
397+
398+
/* Clear Bus Fault pending bit */
399+
SCB->SHCSR &= ~SCB_SHCSR_BUSFAULTPENDED_Msk;
400+
__set_FAULTMASK(0);
401+
402+
return 0;
403+
#else
404+
ARG_UNUSED(regs);
405+
406+
return -ENOTSUP;
407+
#endif
408+
}
409+
410+
static int flash_stm32_option_bytes_disable(const struct device *dev)
411+
{
412+
FLASH_TypeDef *regs = FLASH_STM32_REGS(dev);
413+
414+
#if defined(FLASH_OPTCR_OPTLOCK) /* F2, F4, F7 and H7 */
415+
/*
416+
* Access to option register can be disabled by writing wrong key to
417+
* the key register. Option register will remain disabled until reset.
418+
* Writing wrong key causes a bus fault, so we need to set FAULTMASK to
419+
* disable faults, and clear bus fault pending bit before enabling them
420+
* again.
421+
*/
422+
regs->OPTCR |= FLASH_OPTCR_OPTLOCK;
423+
424+
__set_FAULTMASK(1);
425+
regs->OPTKEYR = 0xffffffff;
426+
427+
/* Clear Bus Fault pending bit */
428+
SCB->SHCSR &= ~SCB_SHCSR_BUSFAULTPENDED_Msk;
429+
__set_FAULTMASK(0);
430+
431+
return 0;
432+
#else
433+
ARG_UNUSED(regs);
434+
435+
return -ENOTSUP;
436+
#endif
437+
}
438+
#endif /* CONFIG_FLASH_STM32_BLOCK_REGISTERS */
439+
379440
static const struct flash_parameters *
380441
flash_stm32_get_parameters(const struct device *dev)
381442
{
@@ -403,6 +464,14 @@ static int flash_stm32_ex_op(const struct device *dev, uint16_t code,
403464
rv = flash_stm32_ex_op_rdp(dev, in, out);
404465
break;
405466
#endif /* CONFIG_FLASH_STM32_READOUT_PROTECTION */
467+
#if defined(CONFIG_FLASH_STM32_BLOCK_REGISTERS)
468+
case FLASH_STM32_EX_OP_BLOCK_OPTION_REG:
469+
rv = flash_stm32_option_bytes_disable(dev);
470+
break;
471+
case FLASH_STM32_EX_OP_BLOCK_CONTROL_REG:
472+
rv = flash_stm32_control_register_disable(dev);
473+
break;
474+
#endif /* CONFIG_FLASH_STM32_BLOCK_REGISTERS */
406475
}
407476

408477
flash_stm32_sem_give(dev);

include/zephyr/drivers/flash/stm32_flash_api_extensions.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,22 @@ enum stm32_ex_ops {
2929
* is returned.
3030
*/
3131
FLASH_STM32_EX_OP_RDP,
32+
/*
33+
* STM32 block option register.
34+
*
35+
* This operation causes option register to be locked until next boot.
36+
* After calling, it's not possible to change option bytes (WP, RDP,
37+
* user bytes).
38+
*/
39+
FLASH_STM32_EX_OP_BLOCK_OPTION_REG,
40+
/*
41+
* STM32 block control register.
42+
*
43+
* This operation causes control register to be locked until next boot.
44+
* After calling, it's not possible to perform basic operation like
45+
* erasing or writing.
46+
*/
47+
FLASH_STM32_EX_OP_BLOCK_CONTROL_REG,
3248
};
3349

3450
#if defined(CONFIG_FLASH_STM32_WRITE_PROTECT)

0 commit comments

Comments
 (0)