Initial commit
Diff: mbed-dev-master/hal/TARGET_FLASH_CMSIS_ALGO/flash_common_algo.c
- Revision:
- 0:bb348c97df44
diff -r 000000000000 -r bb348c97df44 mbed-dev-master/hal/TARGET_FLASH_CMSIS_ALGO/flash_common_algo.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed-dev-master/hal/TARGET_FLASH_CMSIS_ALGO/flash_common_algo.c Wed Sep 16 01:11:49 2020 +0000 @@ -0,0 +1,263 @@ +/* mbed Microcontroller Library + * Copyright (c) 2017 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 "flash_api.h" +#include "flash_data.h" +#include "mbed_critical.h" +#include "mbed_toolchain.h" + +#ifndef DOMAIN_NS + +#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) +#include <arm_cmse.h> +#endif + +#define MBED_FLASH_ALGO_ERASE 1UL +#define MBED_FLASH_ALGO_PROGRAM 2UL + +extern uint32_t SystemCoreClock; + +/* + This binary blob (thumb code) sets r9 (static base) as the code we are jumping to + is PIC (position independent code). + + These are the instructions (r0 is a pointer to arg_t): + push {r5, lr, r4} + mov r5, r9 + push {r5} + ldr r5, [r0, #20] + ldr r3, [r0, #16] + mov r9, r3 + ldr r3, [r0, #12] + ldr r2, [r0, #8] + ldr r1, [r0, #4] + ldr r0, [r0, #0] + blx r5 + pop {r5} + mov r9, r5 + pop {r4-r5, pc} + bx r14 +*/ +static uint32_t jump_to_flash_algo[] = { + 0x464DB530, + 0x6945B420, + 0x46996903, + 0x688268C3, + 0x68006841, + 0xBC2047A8, + 0xBD3046A9 +}; + +// should be called within critical section +static int32_t flash_algo_init(flash_t *obj, uint32_t address, uint32_t function) +{ + args_t arguments = { + .r0 = address, + .r1 = SystemCoreClock, + .r2 = function, + .r3 = 0, + .r9 = (uint32_t)obj->flash_algo->algo_blob + obj->flash_algo->static_base, + .pc = (uint32_t)obj->flash_algo->algo_blob + obj->flash_algo->init + }; + return ((flash_algo_jump_t)(((uint32_t)&jump_to_flash_algo) | 1))(&arguments); +} + +// should be called within critical section +static int32_t flash_algo_uninit(flash_t *obj, uint32_t address, uint32_t function) +{ + args_t arguments = { + .r0 = address, + .r1 = SystemCoreClock, + .r2 = function, + .r3 = 0, + .r9 = (uint32_t)obj->flash_algo->algo_blob + obj->flash_algo->static_base, + .pc = (uint32_t)obj->flash_algo->algo_blob + obj->flash_algo->uninit + }; + return ((flash_algo_jump_t)(((uint32_t)&jump_to_flash_algo) | 1))(&arguments); +} + +#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) +/* Check if address range [start_addr, end_addr] is in non-secure flash + * + * @param obj The flash object + * @param start_addr Start address to check + * @param end_addr End address to check. Could be the same as start_addr to just check start_addr + * for e.g. flash_erase_sector. + * @return 0 for success, -1 for error + */ +static int32_t flash_check_nonsecure(flash_t *obj, uint32_t start_addr, uint32_t end_addr) +{ + /* Check if end address wraps around */ + if (end_addr < start_addr) { + return -1; + } + + /* Check if start address is in non-secure flash */ + if ((start_addr < obj->target_config_ns->flash_start) || + (start_addr >= (obj->target_config_ns->flash_start + obj->target_config_ns->flash_size))) { + return -1; + } + + /* Check if end address is in non-secure flash */ + if (end_addr != start_addr) { + if ((end_addr < obj->target_config_ns->flash_start) || + (end_addr >= (obj->target_config_ns->flash_start + obj->target_config_ns->flash_size))) { + return -1; + } + } + + return 0; +} +#endif + +MBED_NONSECURE_ENTRY int32_t flash_init(flash_t *obj) +{ + flash_set_target_config(obj); + return 0; +} + +MBED_NONSECURE_ENTRY int32_t flash_free(flash_t *obj) +{ + return 0; +} + +MBED_NONSECURE_ENTRY int32_t flash_erase_sector(flash_t *obj, uint32_t address) +{ +#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) + if (cmse_nonsecure_caller()) { + // Confine non-secure access to non-secure flash + if (flash_check_nonsecure(obj, address, address)) { + return -1; + } + } +#endif + + core_util_critical_section_enter(); + flash_algo_init(obj, address, MBED_FLASH_ALGO_ERASE); + + args_t arguments = { + .r0 = address, + .r1 = 0, + .r2 = 0, + .r3 = 0, + .r9 = (uint32_t)obj->flash_algo->algo_blob + obj->flash_algo->static_base, + .pc = (uint32_t)obj->flash_algo->algo_blob + obj->flash_algo->erase_sector + }; + int32_t ret = ((flash_algo_jump_t)(((uint32_t)&jump_to_flash_algo) | 1))(&arguments); + + flash_algo_uninit(obj, address, MBED_FLASH_ALGO_ERASE); + core_util_critical_section_exit(); + return ret ? -1 : 0; +} + +MBED_NONSECURE_ENTRY int32_t flash_program_page(flash_t *obj, uint32_t address, const uint8_t *data, uint32_t size) +{ +#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) + if (cmse_nonsecure_caller()) { + // Confine non-secure access to non-secure flash + if (flash_check_nonsecure(obj, address, address + size - 1)) { + return -1; + } + } +#endif + + core_util_critical_section_enter(); + flash_algo_init(obj, address, MBED_FLASH_ALGO_PROGRAM); + + args_t arguments = { + .r0 = address, + .r1 = size, + .r2 = (uint32_t)data, + .r3 = 0, + .r9 = (uint32_t)obj->flash_algo->algo_blob + obj->flash_algo->static_base, + .pc = (uint32_t)obj->flash_algo->algo_blob + obj->flash_algo->program_page + }; + int32_t ret = ((flash_algo_jump_t)(((uint32_t)&jump_to_flash_algo) | 1))(&arguments); + + flash_algo_uninit(obj, address, MBED_FLASH_ALGO_PROGRAM); + core_util_critical_section_exit(); + return ret ? -1 : 0; +} + +MBED_NONSECURE_ENTRY uint32_t flash_get_sector_size(const flash_t *obj, uint32_t address) +{ +#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) + if (cmse_nonsecure_caller()) { + const sector_info_t *sectors = obj->target_config_ns->sectors; + + if (address >= obj->target_config_ns->flash_start + obj->target_config_ns->flash_size) { + return MBED_FLASH_INVALID_SIZE; + } + + int sector_index = obj->target_config_ns->sector_info_count - 1; + for (; sector_index >= 0; sector_index--) { + if (address >= sectors[sector_index].start) { + return sectors[sector_index].size; + } + } + return MBED_FLASH_INVALID_SIZE; + } +#endif + + const sector_info_t *sectors = obj->target_config->sectors; + + if (address >= obj->target_config->flash_start + obj->target_config->flash_size) { + return MBED_FLASH_INVALID_SIZE; + } + + int sector_index = obj->target_config->sector_info_count - 1; + for (; sector_index >= 0; sector_index--) { + if (address >= sectors[sector_index].start) { + return sectors[sector_index].size; + } + } + return MBED_FLASH_INVALID_SIZE; +} + +MBED_NONSECURE_ENTRY uint32_t flash_get_page_size(const flash_t *obj) +{ +#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) + if (cmse_nonsecure_caller()) { + return obj->target_config_ns->page_size; + } +#endif + + return obj->target_config->page_size; +} + +MBED_NONSECURE_ENTRY uint32_t flash_get_start_address(const flash_t *obj) +{ +#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) + if (cmse_nonsecure_caller()) { + return obj->target_config_ns->flash_start; + } +#endif + + return obj->target_config->flash_start; +} + +MBED_NONSECURE_ENTRY uint32_t flash_get_size(const flash_t *obj) +{ +#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) + if (cmse_nonsecure_caller()) { + return obj->target_config_ns->flash_size; + } +#endif + + return obj->target_config->flash_size; +} + +#endif // #ifndef DOMAIN_NS