[PATCH v2 01/11] ARM: i.MX8M: enable MMU in PBL around fw-external BL32 verify
Johannes Schneider <[email protected]> Sat, 4 Jul 2026 12:26:18 +0000
| Newsgroups | org.infradead.lists.barebox |
|---|---|
| Message-ID | <[email protected]> |
The BL32 fw-external blob is loaded into DRAM by the PBL and then SHA-256-verified inside get_builtin_firmware_ext(). With the MMU off and the D-cache cold that verify walks ~720 KiB through uncached DRAM; on a Cortex-A53 that is ~2 s of pre-BL31 wall-clock every boot. The verify is the only thing anchoring the BL32 content to the signed PBL (HABv4 on i.MX8M only signs/loads what fits in OCRAM = the PBL; BL31/BL32 reach DRAM via PBL copies), so skipping the SHA-256 would be a security regression. Turn the MMU + D-cache on once DRAM is populated, right before the verify + BL31/BL32 memcpy, and drop it again before the BL31 entry (BL31 expects MMU off). The verify drops from ~2 s to ~300 ms and BL31 early-init also benefits from the warm cache. Wrap the enable in imx8m_mmu_early_enable(), which picks the early-DRAM size from the DDR bus width (16 for i.MX8MN, 32 otherwise), rather than open-coding mmu_early_enable() at every call site [1]. Mirrors the Rockchip PBL MMU handling. [1] https://lists.infradead.org/pipermail/barebox/2026-July/056889.html Assisted-by: Claude Opus 4.8 (1M context) Signed-off-by: Johannes Schneider <[email protected]> --- Notes: v2: - Wrap the enable in a new imx8m_mmu_early_enable() that derives the early-DRAM size from the DDR bus width (16 for i.MX8MN, 32 otherwise), instead of open-coding mmu_early_enable() at each call site (Sascha). - Folded into this series (was posted as a standalone patch). - Guard the mmu_early_enable() call with IS_ENABLED(CONFIG_MMU) (it has no !MMU stub), matching arch/arm/cpu/uncompress.c (Copilot). arch/arm/mach-imx/atf.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/arch/arm/mach-imx/atf.c b/arch/arm/mach-imx/atf.c index 948756e26b..0f57a204b7 100644 --- a/arch/arm/mach-imx/atf.c +++ b/arch/arm/mach-imx/atf.c @@ -20,6 +20,7 @@ #include <mach/imx/xload.h> #include <mach/imx/snvs.h> #include <pbl.h> +#include <asm/mmu.h> static void imx_adjust_optee_memory(void **bl32, void **bl32_image, size_t *bl32_size) { @@ -130,6 +131,20 @@ static __noreturn void start_bl31_via_bl_params(void *bl31, void *bl32, * 4. Transfers control to BL31 */ +/* Enable the MMU + D-cache over the i.MX8M early-DRAM window. */ +static void imx8m_mmu_early_enable(void) +{ + unsigned long memsize; + + if (cpu_is_mx8mn()) + memsize = imx8m_barebox_earlymem_size(16); + else + memsize = imx8m_barebox_earlymem_size(32); + + if (IS_ENABLED(CONFIG_MMU)) + mmu_early_enable(MX8M_DDR_CSD1_BASE_ADDR, memsize); +} + static __noreturn void imx8m_tfa_start_bl31(const void *tfa_bin, size_t tfa_size, void *tfa_dest, void *tee_bin, size_t tee_size, void *bl33, void *fdt) @@ -188,6 +203,9 @@ imx8m_tfa_start_bl31(const void *tfa_bin, size_t tfa_size, void *tfa_dest, "r" (tfa_dest - 16) : "cc"); + /* BL31 expects MMU off. */ + mmu_disable(); + /* * If enabled the bl_params are passed via x0 to the TF-A, except for * the i.MX8MQ which doesn't support bl_params yet. @@ -283,6 +301,9 @@ __noreturn void __imx8mm_load_and_start_image_via_tfa(void *fdt, void *bl33) imx8m_setup_snvs(); imx8mm_load_bl33(bl33); + /* Cache DRAM for the BL32 verify + BL31/BL32 memcpy that follow. */ + imx8m_mmu_early_enable(); + if (IS_ENABLED(CONFIG_FIRMWARE_IMX8MM_OPTEE)) { get_builtin_firmware_ext(imx8mm_bl32_bin, bl33, &bl32); get_builtin_firmware(imx8mm_bl31_bin_optee, &bl31); @@ -346,6 +367,9 @@ __noreturn void __imx8mp_load_and_start_image_via_tfa(void *fdt, void *bl33) imx8m_setup_snvs(); imx8mp_load_bl33(bl33); + /* Cache DRAM for the BL32 verify + BL31/BL32 memcpy that follow. */ + imx8m_mmu_early_enable(); + if (IS_ENABLED(CONFIG_FIRMWARE_IMX8MP_OPTEE)) { get_builtin_firmware_ext(imx8mp_bl32_bin, bl33, &bl32); get_builtin_firmware(imx8mp_bl31_bin_optee, &bl31); @@ -409,6 +433,9 @@ __noreturn void __imx8mn_load_and_start_image_via_tfa(void *fdt, void *bl33) imx8m_setup_snvs(); imx8mn_load_bl33(bl33); + /* Cache DRAM for the BL32 verify + BL31/BL32 memcpy that follow. */ + imx8m_mmu_early_enable(); + if (IS_ENABLED(CONFIG_FIRMWARE_IMX8MN_OPTEE)) { get_builtin_firmware_ext(imx8mn_bl32_bin, bl33, &bl32); get_builtin_firmware(imx8mn_bl31_bin_optee, &bl31); @@ -466,6 +493,9 @@ __noreturn void __imx8mq_load_and_start_image_via_tfa(void *fdt, void *bl33) imx8m_setup_snvs(); imx8mq_load_bl33(bl33); + /* Cache DRAM for the BL32 verify + BL31/BL32 memcpy that follow. */ + imx8m_mmu_early_enable(); + if (IS_ENABLED(CONFIG_FIRMWARE_IMX8MQ_OPTEE)) { get_builtin_firmware_ext(imx8mq_bl32_bin, bl33, &bl32); get_builtin_firmware(imx8mq_bl31_bin_optee, &bl31); -- 2.43.0