/* * Copyright (c) 2015, 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 STATUS fwu_nvm_write(unsigned long long offset, const void *buffer, size_t size) { uintptr_t nvm_handle; int ret; size_t length_write; if (offset + size > FLASH_SIZE) return STATUS_OUT_OF_RESOURCES; /* Obtain a handle to the NVM by querying the platfom layer */ plat_get_nvm_handle(&nvm_handle); /* Seek to the given offset. */ ret = io_seek(nvm_handle, IO_SEEK_SET, offset); if (ret != IO_SUCCESS) return STATUS_FAIL; /* Write to the given offset. */ ret = io_write(nvm_handle, (const uintptr_t)buffer, size, &length_write); if ((ret != IO_SUCCESS) || (size != length_write)) return STATUS_FAIL; return STATUS_SUCCESS; } STATUS fwu_nvm_read(unsigned long long offset, void *buffer, size_t size) { uintptr_t nvm_handle; int ret; size_t length_read; if (offset + size > FLASH_SIZE) return STATUS_OUT_OF_RESOURCES; /* Obtain a handle to the NVM by querying the platform layer */ plat_get_nvm_handle(&nvm_handle); /* Seek to the given offset. */ ret = io_seek(nvm_handle, IO_SEEK_SET, offset); if (ret != IO_SUCCESS) return STATUS_FAIL; /* Read from the given offset. */ ret = io_read(nvm_handle, (const uintptr_t)buffer, size, &length_read); if ((ret != IO_SUCCESS) || (size != length_read)) return STATUS_FAIL; return STATUS_SUCCESS; } STATUS fwu_update_fip(unsigned long fip_addr) { uintptr_t nvm_handle; int ret; size_t bytes; int fip_size; unsigned int fip_read; fip_toc_header_t *toc_header; fip_toc_entry_t *toc_entry; /* Obtain a handle to the NVM by querying the platform layer */ plat_get_nvm_handle(&nvm_handle); #if FWU_BL_TEST /* Read the address of backup fip.bin for Firmware Update. */ ret = io_seek(nvm_handle, IO_SEEK_SET, FWU_TFTF_TESTCASE_BUFFER_OFFSET); if (ret != IO_SUCCESS) return STATUS_FAIL; ret = io_read(nvm_handle, (const uintptr_t)&fip_addr, sizeof(bytes), &bytes); if (ret != IO_SUCCESS) return STATUS_FAIL; #endif /* FWU_BL_TEST */ /* If the new FIP address is 0 it means no update. */ if (fip_addr == 0) return STATUS_SUCCESS; /* Set the ToC Header at the base of the buffer */ toc_header = (fip_toc_header_t *)fip_addr; /* Check if this FIP is Valid */ if ((toc_header->name != TOC_HEADER_NAME) || (toc_header->serial_number == 0)) return STATUS_LOAD_ERROR; /* Get to the last NULL TOC entry */ toc_entry = (fip_toc_entry_t *)(toc_header + 1); while (!is_uuid_null(&toc_entry->uuid)) toc_entry++; /* get the total size of this FIP */ fip_size = (int)toc_entry->offset_address; /* Copy the new FIP in DDR. */ memcpy((void *)FIP_IMAGE_TMP_DDR_ADDRESS, (void *)fip_addr, fip_size); /* Update the FIP */ ret = io_seek(nvm_handle, IO_SEEK_SET, 0); if (ret != IO_SUCCESS) return STATUS_FAIL; ret = io_write(nvm_handle, (const uintptr_t)FIP_IMAGE_TMP_DDR_ADDRESS, fip_size, &bytes); if ((ret != IO_SUCCESS) || fip_size != bytes) return STATUS_LOAD_ERROR; /* Read the TOC header after update. */ ret = io_seek(nvm_handle, IO_SEEK_SET, 0); if (ret != IO_SUCCESS) return STATUS_LOAD_ERROR; ret = io_read(nvm_handle, (const uintptr_t)&fip_read, sizeof(bytes), &bytes); if (ret != IO_SUCCESS) return STATUS_FAIL; /* Check if this FIP is Valid */ if (fip_read != TOC_HEADER_NAME) return STATUS_LOAD_ERROR; #if FWU_BL_TEST unsigned int done_flag = FIP_IMAGE_UPDATE_DONE_FLAG; /* Update the TFTF test case buffer with DONE flag */ ret = io_seek(nvm_handle, IO_SEEK_SET, FWU_TFTF_TESTCASE_BUFFER_OFFSET); if (ret != IO_SUCCESS) return STATUS_FAIL; ret = io_write(nvm_handle, (const uintptr_t)&done_flag, 4, &bytes); if (ret != IO_SUCCESS) return STATUS_FAIL; #endif /* FWU_BL_TEST */ INFO("FWU Image update success\n"); return STATUS_SUCCESS; }