/* * Copyright (c) 2021-2023 Arm Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "emulated_flash_drv.h" #include #include #include #include static int32_t is_range_valid(struct emulated_flash_dev_t *flash_dev, uint32_t offset) { uint32_t flash_limit = 0; int32_t rc = 0; flash_limit = (flash_dev->data->sector_count * flash_dev->data->sector_size) - 1; if (offset > flash_limit) { rc = -1; } return rc; } static int32_t is_write_aligned(struct emulated_flash_dev_t *flash_dev, uint32_t param) { int32_t rc = 0; if ((param % flash_dev->data->program_unit) != 0) { rc = -1; } return rc; } static int32_t is_sector_aligned(struct emulated_flash_dev_t *flash_dev, uint32_t offset) { int32_t rc = 0; if ((offset % flash_dev->data->sector_size) != 0) { rc = -1; } return rc; } static int32_t is_secure_alias_needed(uint32_t addr) { int32_t rc = -1; /* Only have to check it if the object is building for secure side */ #if defined(__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) cmse_address_info_t address_info; /* Check if address can be accessed from non-secure */ address_info = cmse_TTA((void*)addr); /* We only care about the security of the address here */ if(address_info.flags.nonsecure_read_ok) { rc = 0; } else { rc = 1; } #else rc = 0; #endif return rc; } static int32_t is_flash_ready_to_write(const uint8_t *start_addr, uint32_t cnt) { int32_t rc = 0; uint32_t i; for (i = 0; i < cnt; i++) { if(start_addr[i] != EMULATED_FLASH_DRV_ERASE_VALUE) { rc = -1; break; } } return rc; } enum emulated_flash_error_t emulated_flash_read_data(struct emulated_flash_dev_t* dev, uint32_t addr, void *data, uint32_t cnt) { uint32_t start_addr = 0; int32_t rc = 0; /* Check flash memory boundaries */ rc = is_range_valid(dev, addr + cnt); if (rc != 0) { return EMULATED_FLASH_ERR_INVALID_PARAM; } /* Check which alias(S or NS) should be used to access the data */ rc = is_secure_alias_needed(addr + dev->memory_base_ns); if(rc == 1) { start_addr = dev->memory_base_s + addr; } else if(rc == 0) { start_addr = dev->memory_base_ns + addr; } /* Flash interface just emulated over SRAM, use memcpy */ memcpy(data, (void *)start_addr, cnt); return EMULATED_FLASH_ERR_NONE; } enum emulated_flash_error_t emulated_flash_program_data(struct emulated_flash_dev_t* dev, uint32_t addr, const void *data, uint32_t cnt) { uint32_t start_addr = 0; int32_t rc = 0; /* Check flash memory boundaries and alignment with minimal write size */ rc = is_range_valid(dev, addr + cnt - 1); rc |= is_write_aligned(dev, addr); rc |= is_write_aligned(dev, cnt); if (rc != 0) { return EMULATED_FLASH_ERR_INVALID_PARAM; } /* Check which alias(S or NS) should be used to access the data */ rc = is_secure_alias_needed(addr + dev->memory_base_ns); if(rc == 1) { start_addr = dev->memory_base_s + addr; } else if(rc == 0) { start_addr = dev->memory_base_ns + addr; } /* Check if the flash area to write the data was erased previously */ rc = is_flash_ready_to_write((const uint8_t*)start_addr, cnt); if (rc != 0) { return EMULATED_FLASH_NOT_READY; } /* Flash interface just emulated over SRAM, use memcpy */ memcpy((void *)start_addr, data, cnt); return EMULATED_FLASH_ERR_NONE; } enum emulated_flash_error_t emulated_flash_erase_sector(struct emulated_flash_dev_t* dev, uint32_t addr) { uint32_t start_addr = 0; int32_t rc = 0; rc = is_range_valid(dev, addr); rc |= is_sector_aligned(dev, addr); if (rc != 0) { return EMULATED_FLASH_ERR_INVALID_PARAM; } /* Check which alias(S or NS) should be used to access the data */ rc = is_secure_alias_needed(addr + dev->memory_base_ns); if(rc == 1) { start_addr = dev->memory_base_s + addr; } else if(rc == 0) { start_addr = dev->memory_base_ns + addr; } /* Flash interface just emulated over SRAM, use memset */ memset((void *)start_addr, dev->data->erased_value, dev->data->sector_size); return EMULATED_FLASH_ERR_NONE; } void emulated_flash_erase_chip(struct emulated_flash_dev_t* dev) { uint32_t i; uint32_t addr = 0; int32_t rc = 0; /* Only check 1 byte, as the whole memory should have the same security */ rc = is_secure_alias_needed(dev->memory_base_ns); if(rc == 1) { addr = dev->memory_base_s; } else if(rc == 0) { addr = dev->memory_base_ns; } for (i = 0; i < dev->data->sector_count; i++) { /* Flash interface just emulated over SRAM, use memset */ memset((void *)addr, dev->data->erased_value, dev->data->sector_size); addr += dev->data->sector_size; } } ARM_FLASH_INFO* emulated_flash_get_info(struct emulated_flash_dev_t* dev) { return dev->data; }