diff --git a/drivers/io/io_mtd.c b/drivers/io/io_mtd.c index 7575fa2503fece37d3ce84482932d3c8638ac659..ba8cecdfbaf0b46391734cdc9692bc1a16bf11e4 100644 --- a/drivers/io/io_mtd.c +++ b/drivers/io/io_mtd.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2019-2021, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -18,8 +18,9 @@ typedef struct { io_mtd_dev_spec_t *dev_spec; uintptr_t base; - unsigned long long offset; /* Offset in bytes */ - unsigned long long size; /* Size of device in bytes */ + unsigned long long pos; /* Offset in bytes */ + unsigned long long size; /* Size of device in bytes */ + unsigned long long extra_offset; /* Extra offset in bytes */ } mtd_dev_state_t; io_type_t device_type_mtd(void); @@ -110,16 +111,47 @@ static int free_dev_info(io_dev_info_t *dev_info) return 0; } +static int mtd_add_extra_offset(mtd_dev_state_t *cur, size_t *extra_offset) +{ + io_mtd_ops_t *ops = &cur->dev_spec->ops; + int ret; + + if (ops->seek == NULL) { + return 0; + } + + ret = ops->seek(cur->base, cur->pos, extra_offset); + if (ret != 0) { + ERROR("%s: Seek error %d\n", __func__, ret); + return ret; + } + + return 0; +} + static int mtd_open(io_dev_info_t *dev_info, const uintptr_t spec, io_entity_t *entity) { mtd_dev_state_t *cur; + io_block_spec_t *region; + size_t extra_offset = 0U; + int ret; assert((dev_info->info != 0UL) && (entity->info == 0UL)); + region = (io_block_spec_t *)spec; cur = (mtd_dev_state_t *)dev_info->info; entity->info = (uintptr_t)cur; - cur->offset = 0U; + cur->base = region->offset; + cur->pos = 0U; + cur->extra_offset = 0U; + + ret = mtd_add_extra_offset(cur, &extra_offset); + if (ret != 0) { + return ret; + } + + cur->base += extra_offset; return 0; } @@ -128,6 +160,8 @@ static int mtd_open(io_dev_info_t *dev_info, const uintptr_t spec, static int mtd_seek(io_entity_t *entity, int mode, signed long long offset) { mtd_dev_state_t *cur; + size_t extra_offset = 0U; + int ret; assert((entity->info != (uintptr_t)NULL) && (offset >= 0)); @@ -140,22 +174,29 @@ static int mtd_seek(io_entity_t *entity, int mode, signed long long offset) return -EINVAL; } - cur->offset = offset; + cur->pos = offset; break; case IO_SEEK_CUR: - if (((cur->offset + (unsigned long long)offset) >= + if (((cur->base + cur->pos + (unsigned long long)offset) >= cur->size) || - ((cur->offset + (unsigned long long)offset) < - cur->offset)) { + ((cur->base + cur->pos + (unsigned long long)offset) < + cur->base + cur->pos)) { return -EINVAL; } - cur->offset += (unsigned long long)offset; + cur->pos += (unsigned long long)offset; break; default: return -EINVAL; } + ret = mtd_add_extra_offset(cur, &extra_offset); + if (ret != 0) { + return ret; + } + + cur->extra_offset = extra_offset; + return 0; } @@ -174,18 +215,19 @@ static int mtd_read(io_entity_t *entity, uintptr_t buffer, size_t length, assert(ops->read != NULL); VERBOSE("Read at %llx into %lx, length %zi\n", - cur->offset, buffer, length); - if ((cur->offset + length) > cur->dev_spec->device_size) { + cur->base + cur->pos, buffer, length); + if ((cur->base + cur->pos + length) > cur->dev_spec->device_size) { return -EINVAL; } - ret = ops->read(cur->offset, buffer, length, out_length); + ret = ops->read(cur->base + cur->pos + cur->extra_offset, buffer, + length, out_length); if (ret < 0) { return ret; } assert(*out_length == length); - cur->offset += *out_length; + cur->pos += *out_length; return 0; } diff --git a/drivers/mtd/nand/core.c b/drivers/mtd/nand/core.c index 44b001e35bf81e1ba2fb7e55a06d14d2908dbefa..9f0331ad739537aa70cbcb807f63e0231c089605 100644 --- a/drivers/mtd/nand/core.c +++ b/drivers/mtd/nand/core.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, STMicroelectronics - All Rights Reserved + * Copyright (c) 2019-2021, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: BSD-3-Clause */ @@ -112,6 +112,47 @@ int nand_read(unsigned int offset, uintptr_t buffer, size_t length, return 0; } +int nand_seek_bb(uintptr_t base, unsigned int offset, size_t *extra_offset) +{ + unsigned int block; + unsigned int offset_block; + unsigned int max_block; + int is_bad; + size_t count_bb = 0U; + + block = base / nand_dev.block_size; + + if (offset != 0U) { + offset_block = (base + offset - 1U) / nand_dev.block_size; + } else { + offset_block = block; + } + + max_block = nand_dev.size / nand_dev.block_size; + + while (block <= offset_block) { + if (offset_block >= max_block) { + return -EIO; + } + + is_bad = nand_dev.mtd_block_is_bad(block); + if (is_bad < 0) { + return is_bad; + } + + if (is_bad == 1) { + count_bb++; + offset_block++; + } + + block++; + } + + *extra_offset = count_bb * nand_dev.block_size; + + return 0; +} + struct nand_device *get_nand_device(void) { return &nand_dev; diff --git a/include/drivers/io/io_mtd.h b/include/drivers/io/io_mtd.h index 1395ff60196a726cc025a7e6e719482c752f480b..2b5d9b1017a35095d2d2feb5aac975a0742a65d9 100644 --- a/include/drivers/io/io_mtd.h +++ b/include/drivers/io/io_mtd.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2019-2021, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -44,11 +44,22 @@ typedef struct io_mtd_ops { * Return 0 on success, a negative error code otherwise. */ int (*write)(unsigned int offset, uintptr_t buffer, size_t length); + + /* + * Look for an offset to be added to the given offset. + * + * @base: Base address of the area. + * @offset: Offset in bytes to start read operation. + * @extra_offset: [out] Offset to be added to the previous offset. + * Return 0 on success, a negative error code otherwise. + */ + int (*seek)(uintptr_t base, unsigned int offset, size_t *extra_offset); } io_mtd_ops_t; typedef struct io_mtd_dev_spec { unsigned long long device_size; unsigned int erase_size; + size_t offset; io_mtd_ops_t ops; } io_mtd_dev_spec_t; diff --git a/include/drivers/nand.h b/include/drivers/nand.h index 1dbb008f9c280407a2a874b58ace092d2b0a82b3..1b78ad41b15cf891f3c723fa5b13ac2a76f52477 100644 --- a/include/drivers/nand.h +++ b/include/drivers/nand.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, STMicroelectronics - All Rights Reserved + * Copyright (c) 2019-2021, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: BSD-3-Clause */ @@ -45,6 +45,16 @@ struct nand_device { int nand_read(unsigned int offset, uintptr_t buffer, size_t length, size_t *length_read); +/* + * Look for an extra offset to be added in case of bad blocks + * + * @base: Base address of the area + * @offset: Byte offset to read from in device + * @extra_offset: [out] Extra offset to be added if bad blocks are found + * Return: 0 on success, a negative errno on failure + */ +int nand_seek_bb(uintptr_t base, unsigned int offset, size_t *extra_offset); + /* * Get NAND device instance * diff --git a/plat/st/common/include/stm32mp_common.h b/plat/st/common/include/stm32mp_common.h index 42d3487024dd6a42a0b5aa238415707a84e90e09..edced71aa247b183a17414c930d82c0a17df2778 100644 --- a/plat/st/common/include/stm32mp_common.h +++ b/plat/st/common/include/stm32mp_common.h @@ -17,6 +17,7 @@ /* Functions to save and get boot context address given by ROM code */ void stm32mp_save_boot_ctx_address(uintptr_t address); uintptr_t stm32mp_get_boot_ctx_address(void); +uint16_t stm32mp_get_boot_itf_selected(void); bool stm32mp_is_single_core(void); bool stm32mp_is_closed_device(void); diff --git a/plat/st/common/stm32mp_common.c b/plat/st/common/stm32mp_common.c index d3de1e14f3ff989ad39a5db85c3a22e46bdf1084..5e5958baa28af199c4f03070f47dc394f8add2d3 100644 --- a/plat/st/common/stm32mp_common.c +++ b/plat/st/common/stm32mp_common.c @@ -28,10 +28,14 @@ unsigned int plat_get_syscnt_freq2(void) } static uintptr_t boot_ctx_address; +static uint16_t boot_itf_selected; void stm32mp_save_boot_ctx_address(uintptr_t address) { + boot_api_context_t *boot_context = (boot_api_context_t *)address; + boot_ctx_address = address; + boot_itf_selected = boot_context->boot_interface_selected; } uintptr_t stm32mp_get_boot_ctx_address(void) @@ -39,6 +43,11 @@ uintptr_t stm32mp_get_boot_ctx_address(void) return boot_ctx_address; } +uint16_t stm32mp_get_boot_itf_selected(void) +{ + return boot_itf_selected; +} + uintptr_t stm32mp_ddrctrl_base(void) { return DDRCTRL_BASE; @@ -105,7 +114,7 @@ int stm32mp_map_ddr_non_cacheable(void) { return mmap_add_dynamic_region(STM32MP_DDR_BASE, STM32MP_DDR_BASE, STM32MP_DDR_MAX_SIZE, - MT_NON_CACHEABLE | MT_RW | MT_NS); + MT_NON_CACHEABLE | MT_RW | MT_SECURE); } int stm32mp_unmap_ddr(void) diff --git a/plat/st/common/stm32mp_dt.c b/plat/st/common/stm32mp_dt.c index 6465c10e838031b3cdfe0b2cc4869e416e05b127..0b35646926f3b76628c99bbc63c928121f2b53ba 100644 --- a/plat/st/common/stm32mp_dt.c +++ b/plat/st/common/stm32mp_dt.c @@ -209,15 +209,24 @@ int dt_get_stdout_uart_info(struct dt_node_info *info) ******************************************************************************/ uint32_t dt_get_ddr_size(void) { + static uint32_t size; int node; + if (size != 0U) { + return size; + } + node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT); if (node < 0) { INFO("%s: Cannot read DDR node in DT\n", __func__); return 0; } - return fdt_read_uint32_default(fdt, node, "st,mem-size", 0); + size = fdt_read_uint32_default(fdt, node, "st,mem-size", 0U); + + flush_dcache_range((uintptr_t)&size, sizeof(uint32_t)); + + return size; } /******************************************************************************* diff --git a/plat/st/stm32mp1/bl2_plat_setup.c b/plat/st/stm32mp1/bl2_plat_setup.c index 91073b89de5e640e73428f7a2370f3a65a9a36b3..3e179fbbf8295cd6b65af99cb019af489a356b78 100644 --- a/plat/st/stm32mp1/bl2_plat_setup.c +++ b/plat/st/stm32mp1/bl2_plat_setup.c @@ -132,7 +132,6 @@ void bl2_el3_early_platform_setup(u_register_t arg0, void bl2_platform_setup(void) { int ret; - uint32_t ddr_ns_size; if (dt_pmic_status() > 0) { initialize_pmic(); @@ -144,24 +143,16 @@ void bl2_platform_setup(void) panic(); } - ddr_ns_size = stm32mp_get_ddr_ns_size(); - assert(ddr_ns_size > 0U); - - /* Map non secure DDR for BL33 load, now with cacheable attribute */ + /* Map DDR for binary load, now with cacheable attribute */ ret = mmap_add_dynamic_region(STM32MP_DDR_BASE, STM32MP_DDR_BASE, - ddr_ns_size, MT_MEMORY | MT_RW | MT_NS); - assert(ret == 0); + STM32MP_DDR_MAX_SIZE, MT_MEMORY | MT_RW | MT_SECURE); + if (ret < 0) { + ERROR("DDR mapping: error %d\n", ret); + panic(); + } #ifdef AARCH32_SP_OPTEE INFO("BL2 runs OP-TEE setup\n"); - - /* Map secure DDR for OP-TEE paged area */ - ret = mmap_add_dynamic_region(STM32MP_DDR_BASE + ddr_ns_size, - STM32MP_DDR_BASE + ddr_ns_size, - STM32MP_DDR_S_SIZE, - MT_MEMORY | MT_RW | MT_SECURE); - assert(ret == 0); - /* Initialize tzc400 after DDR initialization */ stm32mp1_security_setup(); #else diff --git a/plat/st/stm32mp1/stm32mp1_security.c b/plat/st/stm32mp1/stm32mp1_security.c index 195b3a5501b04950de083483902e1f7e6f3a91a2..2ee5f4a85845bf62d44a4d8192175323b57b0393 100644 --- a/plat/st/stm32mp1/stm32mp1_security.c +++ b/plat/st/stm32mp1/stm32mp1_security.c @@ -27,6 +27,45 @@ TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_ETH_ID) | \ TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_DAP_ID) +static unsigned int region_nb; + +static void init_tzc400_begin(unsigned int region0_attr) +{ + tzc400_init(STM32MP1_TZC_BASE); + tzc400_disable_filters(); + + /* Region 0 set to cover all DRAM at 0xC000_0000 */ + tzc400_configure_region0(region0_attr, 0); + + region_nb = 1U; +} + +static void init_tzc400_end(unsigned int action) +{ + tzc400_set_action(action); + tzc400_enable_filters(); +} + +static void tzc400_add_region(unsigned long long region_base, + unsigned long long region_top, bool sec) +{ + unsigned int sec_attr; + unsigned int nsaid_permissions; + + if (sec) { + sec_attr = TZC_REGION_S_RDWR; + nsaid_permissions = 0; + } else { + sec_attr = TZC_REGION_S_NONE; + nsaid_permissions = TZC_REGION_NSEC_ALL_ACCESS_RDWR; + } + + tzc400_configure_region(STM32MP1_FILTER_BIT_ALL, region_nb, region_base, + region_top, sec_attr, nsaid_permissions); + + region_nb++; +} + /******************************************************************************* * Initialize the TrustZone Controller. Configure Region 0 with Secure RW access * and allow Non-Secure masters full access. @@ -38,10 +77,9 @@ static void init_tzc400(void) unsigned long long ddr_ns_size = (unsigned long long)stm32mp_get_ddr_ns_size(); unsigned long long ddr_ns_top = ddr_base + (ddr_ns_size - 1U); + unsigned long long ddr_top __unused; - tzc400_init(STM32MP1_TZC_BASE); - - tzc400_disable_filters(); + init_tzc400_begin(TZC_REGION_S_NONE); /* * Region 1 set to cover all non-secure DRAM at 0xC000_0000. Apply the @@ -49,35 +87,28 @@ static void init_tzc400(void) */ region_base = ddr_base; region_top = ddr_ns_top; - tzc400_configure_region(STM32MP1_FILTER_BIT_ALL, 1, - region_base, - region_top, - TZC_REGION_S_NONE, - TZC_REGION_NSEC_ALL_ACCESS_RDWR); + tzc400_add_region(region_base, region_top, false); #ifdef AARCH32_SP_OPTEE /* Region 2 set to cover all secure DRAM. */ region_base = region_top + 1U; region_top += STM32MP_DDR_S_SIZE; - tzc400_configure_region(STM32MP1_FILTER_BIT_ALL, 2, - region_base, - region_top, - TZC_REGION_S_RDWR, - 0); - - /* Region 3 set to cover non-secure shared memory DRAM. */ - region_base = region_top + 1U; - region_top += STM32MP_DDR_SHMEM_SIZE; - tzc400_configure_region(STM32MP1_FILTER_BIT_ALL, 3, - region_base, - region_top, - TZC_REGION_S_NONE, - TZC_REGION_NSEC_ALL_ACCESS_RDWR); + tzc400_add_region(region_base, region_top, true); + + ddr_top = STM32MP_DDR_BASE + dt_get_ddr_size() - 1U; + if (region_top < ddr_top) { + /* Region 3 set to cover non-secure memory DRAM after BL32. */ + region_base = region_top + 1U; + region_top = ddr_top; + tzc400_add_region(region_base, region_top, false); + } #endif - tzc400_set_action(TZC_ACTION_INT); - - tzc400_enable_filters(); + /* + * Raise an interrupt (secure FIQ) if a NS device tries to access + * secure memory + */ + init_tzc400_end(TZC_ACTION_INT); } /******************************************************************************* @@ -90,23 +121,11 @@ static void early_init_tzc400(void) stm32mp_clk_enable(TZC1); stm32mp_clk_enable(TZC2); - tzc400_init(STM32MP1_TZC_BASE); - - tzc400_disable_filters(); - - /* Region 1 set to cover Non-Secure DRAM at 0xC000_0000 */ - tzc400_configure_region(STM32MP1_FILTER_BIT_ALL, 1, - STM32MP_DDR_BASE, - STM32MP_DDR_BASE + - (STM32MP_DDR_MAX_SIZE - 1U), - TZC_REGION_S_NONE, - TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_A7_ID) | - TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_SDMMC_ID)); + /* Region 0 set to cover all DRAM secure at 0xC000_0000 */ + init_tzc400_begin(TZC_REGION_S_RDWR); /* Raise an exception if a NS device tries to access secure memory */ - tzc400_set_action(TZC_ACTION_ERR); - - tzc400_enable_filters(); + init_tzc400_end(TZC_ACTION_ERR); } /*******************************************************************************