/* * Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of ARM nor the names of its contributors may be used * to endorse or promote products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define FWU_NON_SECURE (0x0) #define FWU_SECURE (0x1) #define FWU_NON_EXEC (0x0) #define FWU_EXEC (0x1) /* Expected number of SMC calls supported in BL1 */ #define BL1_NUM_SMC_CALLS (10) /* Expected version of BL1 SMC implementation */ #define BL1_SMC_VER_VALUE (1) /* This size is used to exercise partial copy */ #define FWU_COPY_PARTIAL_SIZE (0x10) extern const char version_string[]; typedef void (*ns_bl2u_entrypoint_t)(unsigned long); /* * This structure will be used for: * 1. Assigning unique image identifier. * 2. Assigning attribute to FWU image. * (FWU_NON_SECURE/FWU_SECURE) * (FWU_NON_EXEC/FWU_EXEC) */ typedef struct fwu_image_load_desc { unsigned int image_id; unsigned int secure; unsigned int execute; } fwu_image_load_desc_t; static const fwu_image_load_desc_t ns_bl1u_desc[] = { [0] = { /* Initialize FWU_CERT image params */ .image_id = FWU_CERT_ID, .secure = FWU_SECURE, }, [1] = { /* * Initialize SCP_BL2U image params * Not needed for FVP platform. */ .image_id = SCP_BL2U_IMAGE_ID, .secure = FWU_SECURE, }, [2] = { /* Initialize BL2U image params */ .image_id = BL2U_IMAGE_ID, .secure = FWU_SECURE, .execute = FWU_EXEC }, [3] = { /* Initialize NS_BL2U image params */ .image_id = NS_BL2U_IMAGE_ID, } }; unsigned long smc_result; #define CHECK_SMC_RESULT(_r) do { \ if (smc_result != _r) { \ ERROR("NS_BL1U: SMC call failed with result:%lu\n", smc_result);\ panic(); \ } \ } while (0); void ns_bl1u_fwu_smc_call(unsigned int smc_id, unsigned long x1, unsigned long x2, unsigned long x3, unsigned long x4) { smc64_ret_values fwu_result = {0}; smc64_args fwu_params = {smc_id, x1, x2, x3, x4}; fwu_result = tftf_smc64(&fwu_params); smc_result = fwu_result.ret0; } #if FWU_BL_TEST /******************************************************************************* * Test the TF FWU SMC interface. ******************************************************************************/ static void ns_bl1u_fwu_test_main(void) { unsigned int smc_fid; NOTICE("NS_BL1U: *****Starting NS_BL1U FWU test*****\n"); /* Basic FWU SMC handler test cases. */ INFO("NS_BL1U: Calling BL1_SMC_CALL_COUNT\n"); ns_bl1u_fwu_smc_call(BL1_SMC_CALL_COUNT, 0, 0, 0, 0); CHECK_SMC_RESULT(BL1_NUM_SMC_CALLS); INFO("NS_BL1U: Calling BL1_SMC_VERSION\n"); ns_bl1u_fwu_smc_call(BL1_SMC_VERSION, 0, 0, 0, 0); CHECK_SMC_RESULT(BL1_SMC_VER_VALUE); INFO("NS_BL1U: Calling invalid SMC\n"); ns_bl1u_fwu_smc_call(0xdeadbeef, 0, 0, 0, 0); CHECK_SMC_RESULT(SMC_UNKNOWN); /* FWU_SMC_IMAGE_COPY test cases. */ INFO("NS_BL1U: Doing FWU_SMC_IMAGE_COPY test\n"); smc_fid = FWU_SMC_IMAGE_COPY; INFO("NS_BL1U: Calling with invalid image_id\n"); ns_bl1u_fwu_smc_call(smc_fid, 0xdeadbeef, 0, 0, 0); CHECK_SMC_RESULT(-EPERM); INFO("NS_BL1U: Calling with non-secure image_id\n"); ns_bl1u_fwu_smc_call(smc_fid, NS_BL2U_IMAGE_ID, 0, 0, 0); CHECK_SMC_RESULT(-EPERM); INFO("NS_BL1U: Calling with valid args\n"); ns_bl1u_fwu_smc_call(smc_fid, FWU_CERT_ID, PLAT_ARM_FWU_FIP_BASE, 0x20, 0x20); CHECK_SMC_RESULT(STATUS_SUCCESS); INFO("NS_BL1U: Calling to copy an image_id again\n"); ns_bl1u_fwu_smc_call(smc_fid, FWU_CERT_ID, PLAT_ARM_FWU_FIP_BASE, 0x20, 0x20); CHECK_SMC_RESULT(-EPERM); INFO("NS_BL1U: Calling with source address not mapped\n"); ns_bl1u_fwu_smc_call(smc_fid, BL2U_IMAGE_ID, 0, 0, 0); CHECK_SMC_RESULT(-ENOMEM); INFO("NS_BL1U: Calling with source size not mapped\n"); ns_bl1u_fwu_smc_call(smc_fid, BL2U_IMAGE_ID, PLAT_ARM_FWU_FIP_BASE, 0xdeadbeef, 0xdeadbeef); CHECK_SMC_RESULT(-ENOMEM); INFO("NS_BL1U: Calling with image size more than secure mem\n"); ns_bl1u_fwu_smc_call(smc_fid, BL2U_IMAGE_ID, PLAT_ARM_FWU_FIP_BASE, 0x40000, 0x40000); CHECK_SMC_RESULT(-ENOMEM); INFO("NS_BL1U: Calling with image size 0\n"); ns_bl1u_fwu_smc_call(smc_fid, BL2U_IMAGE_ID, PLAT_ARM_FWU_FIP_BASE, 0, 0); CHECK_SMC_RESULT(-ENOMEM); INFO("NS_BL1U: Calling with 1st block size in partial copy\n"); ns_bl1u_fwu_smc_call(smc_fid, BL2U_IMAGE_ID, PLAT_ARM_FWU_FIP_BASE, 0x20, 0x40); CHECK_SMC_RESULT(STATUS_SUCCESS); INFO("NS_BL1U: Calling FWU_SMC_IMAGE_AUTH while copying the image\n"); ns_bl1u_fwu_smc_call(FWU_SMC_IMAGE_AUTH, BL2U_IMAGE_ID, PLAT_ARM_FWU_FIP_BASE, 0x40, 0); CHECK_SMC_RESULT(-EPERM); INFO("NS_BL1U: Calling with last block with invalid source" " in partial copy\n"); ns_bl1u_fwu_smc_call(smc_fid, BL2U_IMAGE_ID, 0, 0x21, 0x40); CHECK_SMC_RESULT(-ENOMEM); INFO("NS_BL1U: Calling with last block size > total size" " in partial copy\n"); ns_bl1u_fwu_smc_call(smc_fid, BL2U_IMAGE_ID, PLAT_ARM_FWU_FIP_BASE, 0x21, 0x40); CHECK_SMC_RESULT(STATUS_SUCCESS); INFO("NS_BL1U: Calling FWU_SMC_IMAGE_AUTH to RESET the image state\n"); ns_bl1u_fwu_smc_call(FWU_SMC_IMAGE_AUTH, BL2U_IMAGE_ID, PLAT_ARM_FWU_FIP_BASE, 0x40, 0); CHECK_SMC_RESULT(-EAUTH); INFO("NS_BL1U: Calling with block size > total size\n"); ns_bl1u_fwu_smc_call(smc_fid, BL2U_IMAGE_ID, PLAT_ARM_FWU_FIP_BASE, 0x21, 0x20); CHECK_SMC_RESULT(STATUS_SUCCESS); INFO("NS_BL1U: Calling FWU_SMC_IMAGE_AUTH to RESET the image state\n"); ns_bl1u_fwu_smc_call(FWU_SMC_IMAGE_AUTH, BL2U_IMAGE_ID, PLAT_ARM_FWU_FIP_BASE, 0x40, 0); CHECK_SMC_RESULT(-EAUTH); /* FWU_SMC_IMAGE_AUTH test cases. */ INFO("NS_BL1U: Doing FWU_SMC_IMAGE_AUTH test\n"); smc_fid = FWU_SMC_IMAGE_AUTH; INFO("NS_BL1U: Calling with invalid image_id\n"); ns_bl1u_fwu_smc_call(smc_fid, 0, 0, 0, 0); CHECK_SMC_RESULT(-EPERM); INFO("NS_BL1U: Calling with secure image not copied\n"); ns_bl1u_fwu_smc_call(smc_fid, BL2U_IMAGE_ID, 0, 0, 0); CHECK_SMC_RESULT(-EPERM); INFO("NS_BL1U: Calling with source address not mapped\n"); ns_bl1u_fwu_smc_call(smc_fid, NS_BL2U_IMAGE_ID, 0, 0, 0); CHECK_SMC_RESULT(-ENOMEM); INFO("NS_BL1U: Calling with source size not mapped\n"); ns_bl1u_fwu_smc_call(smc_fid, NS_BL2U_IMAGE_ID, PLAT_ARM_FWU_FIP_BASE, 0xdeadbeef, 0); CHECK_SMC_RESULT(-ENOMEM); INFO("NS_BL1U: Calling with valid args for copied image\n"); ns_bl1u_fwu_smc_call(smc_fid, FWU_CERT_ID, 0, 0, 0); CHECK_SMC_RESULT(-EAUTH); INFO("NS_BL1U: Calling FWU_SMC_IMAGE_COPY to copy after auth failure\n"); ns_bl1u_fwu_smc_call(FWU_SMC_IMAGE_COPY, FWU_CERT_ID, PLAT_ARM_FWU_FIP_BASE, 0x40, 0x40); CHECK_SMC_RESULT(STATUS_SUCCESS); INFO("NS_BL1U: Calling with valid args for copied image\n"); ns_bl1u_fwu_smc_call(smc_fid, FWU_CERT_ID, 0, 0, 0); CHECK_SMC_RESULT(-EAUTH); /* FWU_SMC_IMAGE_EXECUTE test cases. */ INFO("NS_BL1U: Doing FWU_SMC_IMAGE_EXECUTE test\n"); smc_fid = FWU_SMC_IMAGE_EXECUTE; INFO("NS_BL1U: Calling with invalid image_id\n"); ns_bl1u_fwu_smc_call(smc_fid, 0, 0, 0, 0); CHECK_SMC_RESULT(-EPERM); INFO("NS_BL1U: Calling with non-executable image_id\n"); ns_bl1u_fwu_smc_call(smc_fid, FWU_CERT_ID, 0, 0, 0); CHECK_SMC_RESULT(-EPERM); INFO("NS_BL1U: Calling with un-authenticated image_id\n"); ns_bl1u_fwu_smc_call(smc_fid, BL2U_IMAGE_ID, 0, 0, 0); CHECK_SMC_RESULT(-EPERM); /* FWU_SMC_IMAGE_RESUME test case. */ INFO("NS_BL1U: Calling FWU_SMC_IMAGE_RESUME with invalid args\n"); ns_bl1u_fwu_smc_call(FWU_SMC_IMAGE_RESUME, 0, 0, 0, 0); CHECK_SMC_RESULT(-EPERM); NOTICE("NS_BL1U: *****All FWU test passed*****\n"); } #endif /* FWU_BL_TEST */ /******************************************************************************* * Following are the responsibilities of NS_BL1U image: * Load FWU images from external NVM memory to NS RAM. * Call SMC's to authenticate images. * Jump to NS_BL2U which carries out next FWU steps. ******************************************************************************/ void ns_bl1u_main(void) { int index; unsigned int img_size; int err; unsigned long offset; ns_bl2u_entrypoint_t ns_bl2u_entrypoint = (ns_bl2u_entrypoint_t)NS_BL2U_BASE; const fwu_image_load_desc_t *image_desc; NOTICE("NS_BL1U: %s\n", version_string); NOTICE("NS_BL1U: %s\n", build_message); tftf_arch_setup(); plat_arm_io_setup(); #if FWU_BL_TEST ns_bl1u_fwu_test_main(); #endif for (index = 0; index < ARRAY_SIZE(ns_bl1u_desc); index++) { image_desc = &ns_bl1u_desc[index]; #if PLAT_fvp /* Skip SCP_BL2U loading for FVP */ if (image_desc->image_id == SCP_BL2U_IMAGE_ID) continue; #endif INFO("NS_BL1U: Loading Image:%u\n", image_desc->image_id); img_size = get_image_size(image_desc->image_id); INFO("NS_BL1U: Image size = %d\n", img_size); if (image_desc->secure == FWU_SECURE) { offset = get_image_offset(image_desc->image_id); INFO("NS_BL1U: Calling COPY SMC for partial copy\n"); ns_bl1u_fwu_smc_call(FWU_SMC_IMAGE_COPY, image_desc->image_id, offset, FWU_COPY_PARTIAL_SIZE, img_size); CHECK_SMC_RESULT(0); ns_bl1u_fwu_smc_call(FWU_SMC_IMAGE_COPY, image_desc->image_id, (offset + FWU_COPY_PARTIAL_SIZE), (img_size - FWU_COPY_PARTIAL_SIZE), img_size); CHECK_SMC_RESULT(0); } else { /* The only non-secure image in ns_bl1u_desc[] should be NS_BL2U */ assert(image_desc->image_id == NS_BL2U_IMAGE_ID); err = load_image(image_desc->image_id, NS_BL2U_BASE); if (err) { ERROR("NS_BL1U: Failed to load NS_BL2U\n"); panic(); } offset = NS_BL2U_BASE; } INFO("NS_BL1U: Calling AUTH SMC\n"); ns_bl1u_fwu_smc_call(FWU_SMC_IMAGE_AUTH, image_desc->image_id, offset, img_size, 0); CHECK_SMC_RESULT(0); #if FWU_BL_TEST /* Check if authenticating again the same image returns error. */ INFO("NS_BL1U: TEST Calling SMC to auth again\n"); ns_bl1u_fwu_smc_call(FWU_SMC_IMAGE_AUTH, ns_bl1u_desc[index].image_id, offset, img_size, 0); CHECK_SMC_RESULT(-EPERM); #endif if (image_desc->execute == FWU_EXEC) { INFO("NS_BL1U: Calling EXECUTE SMC\n"); ns_bl1u_fwu_smc_call(FWU_SMC_IMAGE_EXECUTE, image_desc->image_id, 0, 0, 0); CHECK_SMC_RESULT(0); #if FWU_BL_TEST /* Check if executing again the same image returns error. */ INFO("NS_BL1U: TEST Calling SMC to execute again\n"); ns_bl1u_fwu_smc_call(FWU_SMC_IMAGE_EXECUTE, ns_bl1u_desc[index].image_id, 0, 0, 0); CHECK_SMC_RESULT(-EPERM); #endif } } /* * Clean and invalidate the caches. * And disable the MMU before jumping to NS_BL2U. */ disable_mmu_icache(); /* * The argument passed to NS_BL2U is not used currently. * But keeping the argument passing mechanism for future use. */ ns_bl2u_entrypoint(0); panic(); }