// SPDX-License-Identifier: BSD-2-Clause /* * Copyright 2019 Pengutronix * All rights reserved. * Copyright 2023 NXP * * Rouven Czerwinski */ #include #include #include #include #include #include #include #include #include /* * TZASC2_BASE is asserted non null when used. * This is needed to compile the code for i.MX6UL/L * and i.MX8MQ. */ #ifndef TZASC2_BASE #define TZASC2_BASE 0 #else register_phys_mem(MEM_AREA_IO_SEC, TZASC2_BASE, TZASC_SIZE); #endif register_phys_mem(MEM_AREA_IO_SEC, TZASC_BASE, TZASC_SIZE); /* * i.MX6 needs special handling due to the different GPR locations. */ #if defined(CFG_MX6) #if defined(CFG_MX6UL) || defined(CFG_MX6ULL) || \ defined(CFG_MX6SLL) || defined(CFG_MX6SX) register_phys_mem(MEM_AREA_IO_SEC, IOMUXC_GPR_BASE, IOMUXC_SIZE); #else register_phys_mem(MEM_AREA_IO_SEC, IOMUXC_BASE, IOMUXC_SIZE); #endif #elif defined(IOMUXC_GPR_BASE) register_phys_mem(MEM_AREA_IO_SEC, IOMUXC_GPR_BASE, IOMUXC_SIZE); #endif /* Not all platforms support the GPR offsets yet */ #ifndef IOMUXC_GPR9_OFFSET #define IOMUXC_GPR9_OFFSET 0 #endif #ifndef IOMUXC_GPR_GPR10_OFFSET #define IOMUXC_GPR_GPR10_OFFSET 0 #endif #define IMX6_TZASC2_BYP BIT32(1) #define IMX6_TZASC1_BYP BIT32(0) #define IMX8M_LOCK_GPR_TZASC_EN BIT32(16) #define IMX8M_TZASC_ID_SWAP_BYPASS BIT32(1) #define IMX8M_TZASC_EN BIT32(0) /* * A single cur_tzasc_region is enough albeit some i.MX6 SoCs are equipped with * two TZASCs. The imx_configure_tzasc() is the only function performing the * seq. region initialization. */ static uint8_t cur_tzasc_region; static void imx_tzasc_region_init(void) { /* * Always start with region1, since region0 can't be * configured in size */ cur_tzasc_region = 1; } static void imx_tzasc_region_set(uint8_t new_region) { cur_tzasc_region = new_region; } static uint8_t imx_tzasc_region_get(void) { return cur_tzasc_region; } static bool imx6_tzasc_is_enabled(void) { uint32_t mask = 0; vaddr_t addr = 0; paddr_t base = 0; assert(IOMUXC_GPR9_OFFSET != 0); if (IS_ENABLED(CFG_MX6UL) || IS_ENABLED(CFG_MX6ULL) || IS_ENABLED(CFG_MX6SLL) || IS_ENABLED(CFG_MX6SX)) base = IOMUXC_GPR_BASE; else base = IOMUXC_BASE; addr = core_mmu_get_va(base, MEM_AREA_IO_SEC, IOMUXC_SIZE); if (!addr) { EMSG("Failed to get GPR"); return false; } mask = IMX6_TZASC1_BYP; if (IS_ENABLED(CFG_MX6Q) || IS_ENABLED(CFG_MX6D) || IS_ENABLED(CFG_MX6DL) || IS_ENABLED(CFG_MX6QP)) mask |= IMX6_TZASC2_BYP; return (io_read32(addr + IOMUXC_GPR9_OFFSET) & mask) == mask; } static bool imx8m_tzasc_is_enabled(void) { uint32_t mask = 0; vaddr_t addr = 0; assert(IOMUXC_GPR_GPR10_OFFSET != 0); addr = core_mmu_get_va(IOMUXC_GPR_BASE, MEM_AREA_IO_SEC, IOMUXC_SIZE); if (!addr) { EMSG("Failed to get GPR"); return false; } mask = IMX8M_LOCK_GPR_TZASC_EN | IMX8M_TZASC_ID_SWAP_BYPASS | IMX8M_TZASC_EN; return (io_read32(addr + IOMUXC_GPR_GPR10_OFFSET) & mask) == mask; } static bool imx_tzasc_is_enabled(void) { if (!IS_ENABLED(CFG_TZASC_CHECK_ENABLED)) { IMSG("CFG_TZASC_CHECK_ENABLED disabled, please enable"); return true; } if (IS_ENABLED(CFG_MX6)) return imx6_tzasc_is_enabled(); else if (IS_ENABLED(CFG_MX8M)) return imx8m_tzasc_is_enabled(); IMSG("Checking TZASC enable is not supported yet for this platform"); return false; } static void imx_tzc_auto_configure(vaddr_t addr, vaddr_t rsize, uint32_t attr) { vaddr_t addr_imx = 0; uint8_t region = 0; /* * On 8mscale platforms, the TZASC controller for the DRAM protection, * has the memory regions starting at address 0x0 instead of the DRAM * base address (0x40000000) */ if (IS_ENABLED(CFG_MX8M)) addr_imx = addr - CFG_DRAM_BASE; else addr_imx = addr; region = imx_tzasc_region_get(); region = tzc_auto_configure(addr_imx, rsize, attr, region); imx_tzasc_region_set(region); } static TEE_Result imx_tzc_auto_configure_ddr(const struct core_mmu_phys_mem *ddr_mem, void *ptr __unused) { imx_tzc_auto_configure(ddr_mem->addr, ddr_mem->size, TZC_ATTR_SP_NS_RW); return TEE_SUCCESS; } static TEE_Result imx_configure_tzasc(void) { vaddr_t addr[2] = {0}; int end = 1; int i = 0; if (!imx_tzasc_is_enabled()) panic("TZC380 must be enabled before starting OP-TEE"); addr[0] = core_mmu_get_va(TZASC_BASE, MEM_AREA_IO_SEC, 1); if (IS_ENABLED(CFG_MX6Q) || IS_ENABLED(CFG_MX6D) || IS_ENABLED(CFG_MX6DL) || IS_ENABLED(CFG_MX6QP)) { assert(TZASC2_BASE != 0); addr[1] = core_mmu_get_va(TZASC2_BASE, MEM_AREA_IO_SEC, 1); end = 2; } for (i = 0; i < end; i++) { TEE_Result res; tzc_init(addr[i]); imx_tzasc_region_init(); /* * TZC380 is not memory alias aware so an attacker could read * the OP-TEE core memory if the system does support memory * aliasing. * * To fix this region0 needs to be configured as secure access * only (0xc). This is the default if not changed by the * previous running firmware. region0 covers the complete * platform AXI address space. */ if (IS_ENABLED(CFG_TZASC_REGION0_SECURE) && tzc_verify_region0_secure() != TEE_SUCCESS) panic("region0 is not secure configured, non-secure memory alias access possible!"); res = core_mmu_for_each_nsec_ddr(NULL, imx_tzc_auto_configure_ddr); #if defined(CFG_DDR_SIZE) /* Fallback to static configuration if possible */ if (res == TEE_ERROR_NOT_SUPPORTED) { imx_tzc_auto_configure(CFG_DRAM_BASE, CFG_DDR_SIZE, TZC_ATTR_SP_NS_RW); res = TEE_SUCCESS; } #endif if (res != TEE_SUCCESS) panic("NS-RW DRAM setup failed!"); imx_tzc_auto_configure(CFG_TZDRAM_START, CFG_TZDRAM_SIZE, TZC_ATTR_SP_S_RW); imx_tzc_auto_configure(CFG_SHMEM_START, CFG_SHMEM_SIZE, TZC_ATTR_SP_ALL); if (tzc_regions_lockdown() != TEE_SUCCESS) panic("Region lockdown failed!"); tzc_dump_state(); } return TEE_SUCCESS; } static TEE_Result pm_enter_resume(enum pm_op op, uint32_t pm_hint __unused, const struct pm_callback_handle *pm_handle __unused) { /* * Reconfiguration is required because the TZASC is not part of an * always-on power-domain on i.MX8M SoCs. On i.MX6 it part of an * always-on power-domain. */ if (op == PM_OP_RESUME) return imx_configure_tzasc(); return TEE_SUCCESS; } static TEE_Result tzasc_init(void) { register_pm_driver_cb(pm_enter_resume, NULL, "imx-tzasc"); return imx_configure_tzasc(); } driver_init(tzasc_init);