blob: ec8bb719648053c40e878105a0814b1f8712cbb8 [file] [log] [blame]
/*
* Copyright (c) 2018, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <debug.h>
#include <drivers/io/io_fip.h>
#include <firmware_image_package.h>
#include <fwu_nvm.h>
#include <io_storage.h>
#include <platform.h>
#include <platform_def.h>
#include <status.h>
#include <string.h>
#include <uuid_utils.h>
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;
}