From 2ee8abb05ec8ad6e44ec69ba4e428b5f5d823f95 Mon Sep 17 00:00:00 2001 From: Yann Gautier <yann.gautier@st.com> Date: Tue, 15 Sep 2020 14:35:05 +0200 Subject: [PATCH] stm32mp1: apply ETZPC configuration from DT The security configuration of peripherals is retrieved from device tree file. Change-Id: Iccd846462913cae8784dd6d7d613eb22834936a3 Signed-off-by: Yann Gautier <yann.gautier@st.com> --- drivers/st/etzpc/etzpc.c | 50 ++++- plat/st/stm32mp1/include/stm32mp1_private.h | 4 + .../include/stm32mp1_shared_resources.h | 17 ++ plat/st/stm32mp1/stm32mp1_private.c | 22 ++ plat/st/stm32mp1/stm32mp1_shared_resources.c | 206 +++++++++++++++--- 5 files changed, 273 insertions(+), 26 deletions(-) diff --git a/drivers/st/etzpc/etzpc.c b/drivers/st/etzpc/etzpc.c index ff52a22d9..eb1c79cf7 100644 --- a/drivers/st/etzpc/etzpc.c +++ b/drivers/st/etzpc/etzpc.c @@ -66,6 +66,10 @@ struct etzpc_instance { /* Only 1 instance of the ETZPC is expected per platform */ static struct etzpc_instance etzpc_dev; +struct dt_id_attr { + fdt32_t id_attr[STM32MP1_ETZPC_MAX_ID]; +}; + /* * Implementation uses uint8_t to store each securable DECPROT configuration. * When resuming from deep suspend, the DECPROT configurations are restored. @@ -85,6 +89,50 @@ static bool valid_tzma_id(unsigned int id) } #endif +static int etzpc_dt_conf_decprot(int node) +{ + const struct dt_id_attr *conf_list; + void *fdt; + unsigned int i; + int len = 0; + + if (fdt_get_address(&fdt) == 0) { + return -ENOENT; + } + + conf_list = (const struct dt_id_attr *)fdt_getprop(fdt, node, + "st,decprot", &len); + if (conf_list == NULL) { + INFO("No ETZPC configuration in DT, use default\n"); + return 0; + } + + for (i = 0U; i < (unsigned int)len / sizeof(uint32_t); i++) { + enum etzpc_decprot_attributes attr; + uint32_t value; + uint32_t id; + uint32_t mode; + + value = fdt32_to_cpu(conf_list->id_attr[i]); + + id = ((value >> ETZPC_ID_SHIFT) & ETZPC_ID_MASK); + assert(valid_decprot_id(id)); + + mode = (value >> ETZPC_MODE_SHIFT) & ETZPC_MODE_MASK; + attr = stm32mp_etzpc_binding2decprot(mode); + + stm32mp1_register_etzpc_decprot(id, attr); + + etzpc_configure_decprot(id, attr); + + if ((value & ETZPC_LOCK_MASK) != 0U) { + etzpc_lock_decprot(id); + } + } + + return 0; +} + /* * etzpc_configure_decprot : Load a DECPROT configuration * decprot_id : ID of the IP @@ -254,5 +302,5 @@ int etzpc_init(void) VERBOSE("ETZPC version 0x%x", etzpc_dev.revision); - return 0; + return etzpc_dt_conf_decprot(node); } diff --git a/plat/st/stm32mp1/include/stm32mp1_private.h b/plat/st/stm32mp1/include/stm32mp1_private.h index 91ecc21d5..ebbb71824 100644 --- a/plat/st/stm32mp1/include/stm32mp1_private.h +++ b/plat/st/stm32mp1/include/stm32mp1_private.h @@ -9,6 +9,8 @@ #include <stdint.h> +#include <drivers/st/etzpc.h> + enum boot_device_e { BOOT_DEVICE_USB, BOOT_DEVICE_BOARD @@ -27,6 +29,8 @@ enum boot_device_e get_boot_device(void); void stm32mp1_gic_pcpu_init(void); void stm32mp1_gic_init(void); +enum etzpc_decprot_attributes stm32mp_etzpc_binding2decprot(uint32_t mode); + void stm32mp1_syscfg_init(void); void stm32mp1_syscfg_enable_io_compensation(void); void stm32mp1_syscfg_disable_io_compensation(void); diff --git a/plat/st/stm32mp1/include/stm32mp1_shared_resources.h b/plat/st/stm32mp1/include/stm32mp1_shared_resources.h index 3f6367ebe..519a67bad 100644 --- a/plat/st/stm32mp1/include/stm32mp1_shared_resources.h +++ b/plat/st/stm32mp1/include/stm32mp1_shared_resources.h @@ -7,6 +7,8 @@ #ifndef STM32MP1_SHARED_RESOURCES_H #define STM32MP1_SHARED_RESOURCES_H +#include <drivers/st/etzpc.h> + #include <stm32mp_shared_resources.h> #define STM32MP1_SHRES_GPIOZ(i) (STM32MP1_SHRES_GPIOZ_0 + (i)) @@ -35,4 +37,19 @@ enum stm32mp_shres { STM32MP1_SHRES_COUNT }; + +#ifdef STM32MP_SHARED_RESOURCES +/* + * Register a (non-)secure peripheral based on the ETZPC DECPROT configuration + */ +void stm32mp1_register_etzpc_decprot(unsigned int id, + enum etzpc_decprot_attributes attr); +#else +static inline +void stm32mp1_register_etzpc_decprot(unsigned int id, + enum etzpc_decprot_attributes attr) +{ +} +#endif + #endif /* STM32MP1_SHARED_RESOURCES_H */ diff --git a/plat/st/stm32mp1/stm32mp1_private.c b/plat/st/stm32mp1/stm32mp1_private.c index 57c936855..788931701 100644 --- a/plat/st/stm32mp1/stm32mp1_private.c +++ b/plat/st/stm32mp1/stm32mp1_private.c @@ -508,6 +508,28 @@ uint32_t stm32_iwdg_shadow_update(uint32_t iwdg_inst, uint32_t flags) } #endif +/* + * This function allows to split bindings between platform and ETZPC + * HW mapping. If this conversion was done at driver level, the driver + * should include all supported platform bindings. ETZPC may be used on + * other platforms. + */ +enum etzpc_decprot_attributes stm32mp_etzpc_binding2decprot(uint32_t mode) +{ + switch (mode) { + case DECPROT_S_RW: + return ETZPC_DECPROT_S_RW; + case DECPROT_NS_R_S_W: + return ETZPC_DECPROT_NS_R_S_W; + case DECPROT_MCU_ISOLATION: + return ETZPC_DECPROT_MCU_ISOLATION; + case DECPROT_NS_RW: + return ETZPC_DECPROT_NS_RW; + default: + panic(); + } +} + int plat_bind_regulator(struct stm32mp_regulator *regu) { if ((dt_pmic_status() > 0) && is_pmic_regulator(regu)) { diff --git a/plat/st/stm32mp1/stm32mp1_shared_resources.c b/plat/st/stm32mp1/stm32mp1_shared_resources.c index 208e34a8b..14e4fcc03 100644 --- a/plat/st/stm32mp1/stm32mp1_shared_resources.c +++ b/plat/st/stm32mp1/stm32mp1_shared_resources.c @@ -87,6 +87,64 @@ static const char __unused *shres2str_state(unsigned int state) return shres2str_state_tbl[state]; } +struct shres2decprot { + unsigned int shres_id; + unsigned int decprot_id; + const char *decprot_str; +}; + +#define SHRES2DECPROT(shres, decprot, str) { \ + .shres_id = shres, \ + .decprot_id = decprot, \ + .decprot_str = str, \ + } + +#define SHRES_INVALID ~0U + +static const struct shres2decprot shres2decprot_tbl[] = { + SHRES2DECPROT(STM32MP1_SHRES_IWDG1, STM32MP1_ETZPC_IWDG1_ID, "IWDG1"), + SHRES2DECPROT(STM32MP1_SHRES_USART1, STM32MP1_ETZPC_USART1_ID, "UART1"), + SHRES2DECPROT(STM32MP1_SHRES_SPI6, STM32MP1_ETZPC_SPI6_ID, "SPI6"), + SHRES2DECPROT(STM32MP1_SHRES_I2C4, STM32MP1_ETZPC_I2C4_ID, "I2C4"), + SHRES2DECPROT(STM32MP1_SHRES_RNG1, STM32MP1_ETZPC_RNG1_ID, "RNG1"), + SHRES2DECPROT(STM32MP1_SHRES_HASH1, STM32MP1_ETZPC_HASH1_ID, "HASH1"), + SHRES2DECPROT(STM32MP1_SHRES_CRYP1, STM32MP1_ETZPC_CRYP1_ID, "CRYP1"), + SHRES2DECPROT(STM32MP1_SHRES_I2C6, STM32MP1_ETZPC_I2C6_ID, "I2C6"), + /* Below are specific IDs without a 1-to-1 mapping to SHRES IDs */ + SHRES2DECPROT(SHRES_INVALID, STM32MP1_ETZPC_STGENC_ID, "STGEN"), + SHRES2DECPROT(SHRES_INVALID, STM32MP1_ETZPC_BKPSRAM_ID, "BKPSRAM"), + SHRES2DECPROT(SHRES_INVALID, STM32MP1_ETZPC_DDRCTRL_ID, "DDRCTRL"), + SHRES2DECPROT(SHRES_INVALID, STM32MP1_ETZPC_DDRPHYC_ID, "DDRPHY"), +}; + +static unsigned int decprot2shres(unsigned int decprot_id) +{ + uint32_t i; + + for (i = 0; i < ARRAY_SIZE(shres2decprot_tbl); i++) { + if (shres2decprot_tbl[i].decprot_id == decprot_id) { + return shres2decprot_tbl[i].shres_id; + } + } + + VERBOSE("No shared resource %u", decprot_id); + return SHRES_INVALID; +} + +static const char *decprot2str(unsigned int decprot_id) +{ + size_t i; + + for (i = 0; i < ARRAY_SIZE(shres2decprot_tbl); i++) { + if (shres2decprot_tbl[i].decprot_id == decprot_id) { + return shres2decprot_tbl[i].decprot_str; + } + } + + ERROR("Invalid ID %u", decprot_id); + panic(); +} + /* Get resource state: these accesses lock the registering support */ static void lock_registering(void) { @@ -334,6 +392,53 @@ void stm32mp_register_non_secure_gpio(unsigned int bank, unsigned int pin) } } +void stm32mp1_register_etzpc_decprot(unsigned int id, + enum etzpc_decprot_attributes attr) +{ + unsigned int state = SHRES_SECURE; + unsigned int id_shres; + + switch (attr) { + case ETZPC_DECPROT_S_RW: + break; + case ETZPC_DECPROT_NS_R_S_W: + case ETZPC_DECPROT_MCU_ISOLATION: + case ETZPC_DECPROT_NS_RW: + state = SHRES_NON_SECURE; + break; + default: + panic(); + } + + switch (id) { + case STM32MP1_ETZPC_STGENC_ID: + case STM32MP1_ETZPC_BKPSRAM_ID: + /* We assume these must always be assigned to secure world */ + if (state != SHRES_SECURE) { + panic(); + } + break; + case STM32MP1_ETZPC_DDRCTRL_ID: + case STM32MP1_ETZPC_DDRPHYC_ID: + /* allow write only for secure world */ + if ((attr != ETZPC_DECPROT_S_RW) && + (attr != ETZPC_DECPROT_NS_R_S_W)) { + panic(); + } + break; + default: + id_shres = decprot2shres(id); + if (id_shres == SHRES_INVALID) { + if (state == SHRES_SECURE) { + panic(); + } + } else { + register_periph(id_shres, state); + } + break; + } +} + static bool stm32mp_gpio_bank_is_non_secure(unsigned int bank) { unsigned int non_secure = 0U; @@ -379,12 +484,15 @@ bool stm32mp_nsec_can_access_clock(unsigned long clock_id) enum stm32mp_shres shres_id = STM32MP1_SHRES_COUNT; switch (clock_id) { + case BSEC: + case CK_AXI: case CK_CSI: case CK_HSE: case CK_HSE_DIV2: case CK_HSI: case CK_LSE: case CK_LSI: + case CK_MPU: case PLL1_P: case PLL1_Q: case PLL1_R: @@ -499,33 +607,81 @@ static enum etzpc_decprot_attributes shres2decprot_attr(enum stm32mp_shres id) return ETZPC_DECPROT_S_RW; } -static void set_etzpc_secure_configuration(void) +static bool check_decprot(unsigned int id, enum etzpc_decprot_attributes exp) { - /* Some system peripherals shall be secure */ - etzpc_configure_decprot(STM32MP1_ETZPC_STGENC_ID, ETZPC_DECPROT_S_RW); - etzpc_configure_decprot(STM32MP1_ETZPC_BKPSRAM_ID, ETZPC_DECPROT_S_RW); - etzpc_configure_decprot(STM32MP1_ETZPC_DDRCTRL_ID, - ETZPC_DECPROT_NS_R_S_W); - etzpc_configure_decprot(STM32MP1_ETZPC_DDRPHYC_ID, - ETZPC_DECPROT_NS_R_S_W); - - /* Configure ETZPC with peripheral registering */ - etzpc_configure_decprot(STM32MP1_ETZPC_CRYP1_ID, - shres2decprot_attr(STM32MP1_SHRES_CRYP1)); - etzpc_configure_decprot(STM32MP1_ETZPC_HASH1_ID, - shres2decprot_attr(STM32MP1_SHRES_HASH1)); - etzpc_configure_decprot(STM32MP1_ETZPC_I2C4_ID, - shres2decprot_attr(STM32MP1_SHRES_I2C4)); - etzpc_configure_decprot(STM32MP1_ETZPC_I2C6_ID, - shres2decprot_attr(STM32MP1_SHRES_I2C6)); - etzpc_configure_decprot(STM32MP1_ETZPC_IWDG1_ID, - shres2decprot_attr(STM32MP1_SHRES_IWDG1)); - etzpc_configure_decprot(STM32MP1_ETZPC_RNG1_ID, - shres2decprot_attr(STM32MP1_SHRES_RNG1)); - etzpc_configure_decprot(STM32MP1_ETZPC_USART1_ID, + enum etzpc_decprot_attributes cur = etzpc_get_decprot(id); + + if (cur == exp) { + return true; + } + + switch (exp) { + case ETZPC_DECPROT_NS_RW: + if (cur == ETZPC_DECPROT_S_RW) { + INFO("ETZPC: %s (%d) could be non secure\n", + decprot2str(id), id); + } + return true; + + case ETZPC_DECPROT_S_RW: + ERROR("ETZPC: %s (%d) expected secure but DECPROT = %d\n", + decprot2str(id), id, cur); + break; + + case ETZPC_DECPROT_NS_R_S_W: + case ETZPC_DECPROT_MCU_ISOLATION: + break; + default: + panic(); + } + + return false; +} + +static void check_etzpc_secure_configuration(void) +{ + bool error = false; + + assert(registering_locked); + + error |= !check_decprot(STM32MP1_ETZPC_STGENC_ID, ETZPC_DECPROT_S_RW); + + error |= !check_decprot(STM32MP1_ETZPC_BKPSRAM_ID, ETZPC_DECPROT_S_RW); + + error |= !check_decprot(STM32MP1_ETZPC_USART1_ID, shres2decprot_attr(STM32MP1_SHRES_USART1)); - etzpc_configure_decprot(STM32MP1_ETZPC_SPI6_ID, + + error |= !check_decprot(STM32MP1_ETZPC_I2C4_ID, + shres2decprot_attr(STM32MP1_SHRES_I2C4)); + + error |= !check_decprot(STM32MP1_ETZPC_SPI6_ID, shres2decprot_attr(STM32MP1_SHRES_SPI6)); + + error |= !check_decprot(STM32MP1_ETZPC_RNG1_ID, + shres2decprot_attr(STM32MP1_SHRES_RNG1)); + + error |= !check_decprot(STM32MP1_ETZPC_HASH1_ID, + shres2decprot_attr(STM32MP1_SHRES_HASH1)); + + error |= !check_decprot(STM32MP1_ETZPC_CRYP1_ID, + shres2decprot_attr(STM32MP1_SHRES_CRYP1)); + + error |= !((check_decprot(STM32MP1_ETZPC_DDRCTRL_ID, + ETZPC_DECPROT_NS_R_S_W)) || + (check_decprot(STM32MP1_ETZPC_DDRCTRL_ID, + ETZPC_DECPROT_S_RW))); + + error |= !((check_decprot(STM32MP1_ETZPC_DDRPHYC_ID, + ETZPC_DECPROT_NS_R_S_W)) || + (check_decprot(STM32MP1_ETZPC_DDRPHYC_ID, + ETZPC_DECPROT_S_RW))); + + error |= !check_decprot(STM32MP1_ETZPC_I2C6_ID, + shres2decprot_attr(STM32MP1_SHRES_I2C6)); + + if (error) { + panic(); + } } static void check_rcc_secure_configuration(void) @@ -592,6 +748,6 @@ void stm32mp_lock_periph_registering(void) print_shared_resources_state(); check_rcc_secure_configuration(); - set_etzpc_secure_configuration(); + check_etzpc_secure_configuration(); set_gpio_secure_configuration(); } -- GitLab