From 6f994b8e3ac868ffb1fba35473c753e65dcd1b5e Mon Sep 17 00:00:00 2001 From: Tom Hughes Date: Tue, 2 Jul 2019 16:53:45 -0700 Subject: hatch_fp: Add RDP (read protection) support to STM32F4 BRANCH=none BUG=b:125419658 TEST=Remove "-U" flag in STM32MON_READ_FLAGS in flash_fp_mcu_common.sh flash_fp_mcu -r foo.bin => success hexdump foo.bin => valid data ectool --name=cros_fp flashprotect enable ectool --name=cros_fp reboot_ec flash_fp_mcu -r foo.bin => fails Add "-U" flag back to STM32MON_READ_FLAGS in flash_fp_mcu_common.sh flash_fp_mcu -r foo.bin => success hexdump foo.bin => all 0xFF Change-Id: Ic3ec18262e653b72baf239caa8db12186a63613c Signed-off-by: Tom Hughes Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/1692220 Reviewed-by: Nicolas Boichat --- board/hatch_fp/board.h | 2 +- chip/stm32/flash-f.c | 121 ++++++++++++++++++++++++++++++++++++++++- chip/stm32/flash-f.h | 26 +++++++++ chip/stm32/flash-stm32f3.c | 7 +++ chip/stm32/registers-stm32f4.h | 7 ++- include/config.h | 6 +- 6 files changed, 163 insertions(+), 6 deletions(-) create mode 100644 chip/stm32/flash-f.h diff --git a/board/hatch_fp/board.h b/board/hatch_fp/board.h index 9829b6c4a1..c8b8bc726e 100644 --- a/board/hatch_fp/board.h +++ b/board/hatch_fp/board.h @@ -68,7 +68,7 @@ * We want to prevent flash readout, and use it as indicator of protection * status. */ -/*TODO(b/125419658): enable CONFIG_FLASH_READOUT_PROTECTION_AS_PSTATE*/ +#define CONFIG_FLASH_READOUT_PROTECTION_AS_PSTATE /* the UART console is on USART1 */ #undef CONFIG_UART_CONSOLE diff --git a/chip/stm32/flash-f.c b/chip/stm32/flash-f.c index 8518485caa..5bfec02a62 100644 --- a/chip/stm32/flash-f.c +++ b/chip/stm32/flash-f.c @@ -5,10 +5,12 @@ /* Common flash memory module for STM32F and STM32F0 */ +#include #include "battery.h" #include "console.h" #include "clock.h" #include "flash.h" +#include "flash-f.h" #include "hooks.h" #include "registers.h" #include "panic.h" @@ -18,6 +20,9 @@ #include "util.h" #include "watchdog.h" +#define CPRINTF(format, args...) cprintf(CC_SYSTEM, format, ## args) +#define CPRINTS(format, args...) cprints(CC_SYSTEM, format, ## args) + /* * Approximate number of CPU cycles per iteration of the loop when polling * the flash status @@ -35,6 +40,19 @@ /* 20ms < tERASE < 40ms on F0/F3, for 1K / 2K sector size. */ #define FLASH_ERASE_TIMEOUT_US 40000 +#if defined(CONFIG_FLASH_READOUT_PROTECTION_AS_PSTATE) +#if !defined(CHIP_FAMILY_STM32F4) +#error "CONFIG_FLASH_READOUT_PROTECTION_AS_PSTATE should work with all STM32F " +"series chips, but has not been tested" +#endif /* !CHIP_FAMILY_STM32F4 */ +#endif /* CONFIG_FLASH_READOUT_PROTECTION_AS_PSTATE */ + +/* Forward declarations */ +#if defined(CONFIG_FLASH_READOUT_PROTECTION_AS_PSTATE) +static enum flash_rdp_level flash_physical_get_rdp_level(void); +static int flash_physical_set_rdp_level(enum flash_rdp_level level); +#endif /* CONFIG_FLASH_READOUT_PROTECTION_AS_PSTATE */ + static inline int calculate_flash_timeout(void) { return (FLASH_WRITE_TIMEOUT_US * @@ -248,6 +266,23 @@ static int write_optb(int byte, uint8_t value) } #endif +#if defined(CONFIG_FLASH_READOUT_PROTECTION_AS_PSTATE) +/** + * @return true if RDP (read protection) Level 1 or 2 enabled, false otherwise + */ +bool is_flash_rdp_enabled(void) +{ + enum flash_rdp_level level = flash_physical_get_rdp_level(); + + if (level == FLASH_RDP_LEVEL_INVALID) { + CPRINTS("ERROR: unable to read RDP level"); + return false; + } + + return level != FLASH_RDP_LEVEL_0; +} +#endif /* CONFIG_FLASH_READOUT_PROTECTION_AS_PSTATE */ + /*****************************************************************************/ /* Physical layer APIs */ @@ -421,6 +456,28 @@ static int flash_physical_get_protect_at_boot(int block) return !(STM32_OPTB_WP & STM32_OPTB_nWRP(block)); } +static int flash_physical_protect_at_boot_update_rdp_pstate(uint32_t new_flags) +{ +#if defined(CONFIG_FLASH_READOUT_PROTECTION_AS_PSTATE) + int rv = EC_SUCCESS; + + bool rdp_enable = (new_flags & EC_FLASH_PROTECT_RO_AT_BOOT) != 0; + + /* + * This is intentionally a one-way latch. Once we have enabled RDP + * Level 1, we will only allow going back to Level 0 using the + * bootloader (e.g., "stm32mon -U") since transitioning from Level 1 to + * Level 0 triggers a mass erase. + */ + if (rdp_enable) + rv = flash_physical_set_rdp_level(FLASH_RDP_LEVEL_1); + + return rv; +#else + return EC_SUCCESS; +#endif +} + int flash_physical_protect_at_boot(uint32_t new_flags) { int block; @@ -452,7 +509,7 @@ int flash_physical_protect_at_boot(uint32_t new_flags) } - return EC_SUCCESS; + return flash_physical_protect_at_boot_update_rdp_pstate(new_flags); } static void unprotect_all_blocks(void) @@ -545,6 +602,68 @@ static int registers_need_reset(void) return 0; } +#if defined(CONFIG_FLASH_READOUT_PROTECTION_AS_PSTATE) +/** + * Set Flash RDP (read protection) level. + * + * @note Does not take effect until reset. + * + * @param level new RDP (read protection) level to set + * @return EC_SUCCESS on success, other on failure + */ +int flash_physical_set_rdp_level(enum flash_rdp_level level) +{ + uint32_t reg_level; + + switch (level) { + case FLASH_RDP_LEVEL_0: + /* + * Asserting by default since we don't want to inadvertently + * go from Level 1 to Level 0, which triggers a mass erase. + * Remove assert if you want to use it. + */ + ASSERT(false); + reg_level = FLASH_OPTCR_RDP_LEVEL_0; + break; + case FLASH_RDP_LEVEL_1: + reg_level = FLASH_OPTCR_RDP_LEVEL_1; + break; + case FLASH_RDP_LEVEL_2: + /* + * Asserting by default since it's permanent (there is no + * way to reverse). Remove assert if you want to use it. + */ + ASSERT(false); + reg_level = FLASH_OPTCR_RDP_LEVEL_2; + break; + default: + return EC_ERROR_INVAL; + } + + return write_optb(FLASH_OPTCR_RDP_MASK, reg_level); +} + +/** + * @return On success, current flash read protection level. + * On failure, FLASH_RDP_LEVEL_INVALID + */ +enum flash_rdp_level flash_physical_get_rdp_level(void) +{ + uint32_t level = (STM32_FLASH_OPTCR & FLASH_OPTCR_RDP_MASK); + + switch (level) { + case FLASH_OPTCR_RDP_LEVEL_0: + return FLASH_RDP_LEVEL_0; + case FLASH_OPTCR_RDP_LEVEL_1: + return FLASH_RDP_LEVEL_1; + case FLASH_OPTCR_RDP_LEVEL_2: + return FLASH_RDP_LEVEL_2; + default: + return FLASH_RDP_LEVEL_INVALID; + } +} +#endif /* CONFIG_FLASH_READOUT_PROTECTION_AS_PSTATE */ + /*****************************************************************************/ /* High-level APIs */ diff --git a/chip/stm32/flash-f.h b/chip/stm32/flash-f.h new file mode 100644 index 0000000000..cbbe6ec86f --- /dev/null +++ b/chip/stm32/flash-f.h @@ -0,0 +1,26 @@ +/* Copyright 2019 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef __CROS_EC_STM32_FLASH_F_H +#define __CROS_EC_STM32_FLASH_F_H + +#include + +enum flash_rdp_level { + FLASH_RDP_LEVEL_INVALID = -1, /**< Error occurred. */ + FLASH_RDP_LEVEL_0, /**< No read protection. */ + FLASH_RDP_LEVEL_1, /**< Reading flash is disabled while in + * bootloader mode or JTAG attached. + * Changing to Level 0 from this level + * triggers mass erase. + */ + FLASH_RDP_LEVEL_2, /**< Same as Level 1, but is permanent + * and can never be disabled. + */ +}; + +bool is_flash_rdp_enabled(void); + +#endif /* __CROS_EC_STM32_FLASH_F_H */ diff --git a/chip/stm32/flash-stm32f3.c b/chip/stm32/flash-stm32f3.c index f0c8028f61..efa74c90cd 100644 --- a/chip/stm32/flash-stm32f3.c +++ b/chip/stm32/flash-stm32f3.c @@ -5,8 +5,10 @@ /* Flash memory module for stm32f3 and stm32f4 */ +#include #include "common.h" #include "flash.h" +#include "flash-f.h" #include "hooks.h" #include "registers.h" #include "system.h" @@ -103,6 +105,11 @@ uint32_t flash_physical_get_protect_flags(void) if (entire_flash_locked) flags |= EC_FLASH_PROTECT_ALL_NOW; +#if defined(CONFIG_FLASH_READOUT_PROTECTION_AS_PSTATE) + if (is_flash_rdp_enabled()) + flags |= EC_FLASH_PROTECT_RO_AT_BOOT; +#endif + return flags; } diff --git a/chip/stm32/registers-stm32f4.h b/chip/stm32/registers-stm32f4.h index 06ac8f61ad..aef2f87f6f 100644 --- a/chip/stm32/registers-stm32f4.h +++ b/chip/stm32/registers-stm32f4.h @@ -729,7 +729,12 @@ typedef volatile struct stm32_spi_regs stm32_spi_regs_t; #define FLASH_OPTLOCK BIT(0) #define FLASH_OPTSTRT BIT(1) #define STM32_FLASH_BOR_LEV_OFFSET (2) -#define STM32_FLASH_RDP_MASK (0xFF << 8) +#define FLASH_OPTCR_RDP_SHIFT (8) +#define FLASH_OPTCR_RDP_MASK (0xFF << FLASH_OPTCR_RDP_SHIFT) +#define FLASH_OPTCR_RDP_LEVEL_0 (0xAA << FLASH_OPTCR_RDP_SHIFT) +/* RDP Level 1: Anything but 0xAA/0xCC */ +#define FLASH_OPTCR_RDP_LEVEL_1 (0x00 << FLASH_OPTCR_RDP_SHIFT) +#define FLASH_OPTCR_RDP_LEVEL_2 (0xCC << FLASH_OPTCR_RDP_SHIFT) #define STM32_FLASH_nWRP_OFFSET (16) #define STM32_FLASH_nWRP(_bank) BIT(_bank + STM32_FLASH_nWRP_OFFSET) #define STM32_FLASH_nWRP_ALL (0xFF << STM32_FLASH_nWRP_OFFSET) diff --git a/include/config.h b/include/config.h index 14670e0be6..d1a4dfc8d0 100644 --- a/include/config.h +++ b/include/config.h @@ -1677,7 +1677,7 @@ * could allow protected regions readback. * * TODO(crbug.com/888109): Implementation is currently only available on - * STM32H7, and requires more documentation. + * STM32H7 and STM32F4, and requires more documentation. */ #undef CONFIG_FLASH_READOUT_PROTECTION_AS_PSTATE @@ -4748,8 +4748,8 @@ #error "Flash readout protection and PSTATE may not work as intended." #endif -#ifndef CHIP_FAMILY_STM32H7 -#error "Flash readout protection only implemented on STM32H7." +#if !defined(CHIP_FAMILY_STM32H7) && !defined(CHIP_FAMILY_STM32F4) +#error "Flash readout protection only implemented on STM32H7 and STM32F4." #endif #endif /* CONFIG_FLASH_READOUT_PROTECTION_AS_PSTATE */ -- cgit v1.2.1