1 /* 2 * Copyright (c) 2023 Raspberry Pi (Trading) Ltd. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #ifndef _PICO_FLASH_H 8 #define _PICO_FLASH_H 9 10 #include "pico.h" 11 12 #include "hardware/flash.h" 13 #include "pico/time.h" 14 15 /** \file pico/flash.h 16 * \defgroup pico_flash pico_flash 17 * 18 * High level flash API 19 * 20 * Flash cannot be erased or written to when in XIP mode. However the system cannot directly access memory in the flash 21 * address space when not in XIP mode. 22 * 23 * It is therefore critical that no code or data is being read from flash while flash is been written or erased. 24 * 25 * If only one core is being used, then the problem is simple - just disable interrupts; however if code is running on 26 * the other core, then it has to be asked, nicely, to avoid flash for a bit. This is hard to do if you don't have 27 * complete control of the code running on that core at all times. 28 * 29 * This library provides a \ref flash_safe_execute method which calls a function back having sucessfully gotten 30 * into a state where interrupts are disabled, and the other core is not executing or reading from flash. 31 * 32 * How it does this is dependent on the supported environment (Free RTOS SMP or pico_multicore). Additionally 33 * the user can provide their own mechanism by providing a strong definition of \ref get_flash_safety_helper(). 34 * 35 * Using the default settings, flash_safe_execute will only call the callback function if the state is safe 36 * otherwise returning an error (or an assert depending on \ref PICO_FLASH_ASSERT_ON_UNSAFE). 37 * 38 * There are conditions where safety would not be guaranteed: 39 * 40 * 1. FreeRTOS smp with `configNUM_CORES=1` - FreeRTOS still uses pico_multicore in this case, so \ref flash_safe_execute 41 * cannot know what the other core is doing, and there is no way to force code execution between a FreeRTOS core 42 * and a non FreeRTOS core. 43 * 2. FreeRTOS non SMP with pico_multicore - Again, there is no way to force code execution between a FreeRTOS core and 44 * a non FreeRTOS core. 45 * 3. pico_multicore without \ref flash_safe_execute_core_init() having been called on the other core - The 46 * \ref flash_safe_execute method does not know if code is executing on the other core, so it has to assume it is. Either 47 * way, it is not able to intervene if \ref flash_safe_execute_core_init() has not been called on the other core. 48 * 49 * Fortunately, all is not lost in this situation, you may: 50 * 51 * * Set \ref PICO_FLASH_ASSUME_CORE0_SAFE=1 to explicitly say that core 0 is never using flash. 52 * * Set \ref PICO_FLASH_ASSUME_CORE1_SAFE=1 to explicitly say that core 1 is never using flash. 53 */ 54 55 #ifdef __cplusplus 56 extern "C" { 57 #endif 58 59 /** 60 * Initialize a core such that the other core can lock it out during \ref flash_safe_execute. 61 * \ingroup pico_flash 62 * 63 * \note This is not necessary for FreeRTOS SMP, but should be used when launching via \ref multicore_launch_core1 64 * \return true on success; there is no need to call \ref flash_safe_execute_core_deinit() on failure. 65 */ 66 bool flash_safe_execute_core_init(void); 67 68 /** 69 * De-initialize work done by \ref flash_safe_execute_core_init 70 * \ingroup pico_flash 71 * \return true on success 72 */ 73 bool flash_safe_execute_core_deinit(void); 74 75 /** 76 * Execute a function with IRQs disabled and with the other core also not executing/reading flash 77 * \ingroup pico_flash 78 * 79 * \param func the function to call 80 * \param param the parameter to pass to the function 81 * \param enter_exit_timeout_ms the timeout for each of the enter/exit phases when coordinating with the other core 82 * 83 * \return PICO_OK on success (the function will have been called). 84 * PICO_TIMEOUT on timeout (the function may have been called). 85 * PICO_ERROR_NOT_PERMITTED if safe execution is not possible (the function will not have been called). 86 * PICO_ERROR_INSUFFICIENT_RESOURCES if the method fails due to dynamic resource exhaustion (the function will not have been called) 87 * \note if \ref PICO_FLASH_ASSERT_ON_UNSAFE is 1, this function will assert in debug mode vs returning 88 * PICO_ERROR_NOT_PERMITTED 89 */ 90 int flash_safe_execute(void (*func)(void *), void *param, uint32_t enter_exit_timeout_ms); 91 92 // PICO_CONFIG: PICO_FLASH_ASSERT_ON_UNSAFE, Assert in debug mode rather than returning an error if flash_safe_execute cannot guarantee safety to catch bugs early, type=bool, default=1, group=pico_flash 93 #ifndef PICO_FLASH_ASSERT_ON_UNSAFE 94 #define PICO_FLASH_ASSERT_ON_UNSAFE 1 95 #endif 96 97 // PICO_CONFIG: PICO_FLASH_ASSUME_CORE0_SAFE, Assume that core 0 will never be accessing flash and so doesn't need to be considered during flash_safe_execute, type=bool, default=0, group=pico_flash 98 #ifndef PICO_FLASH_ASSUME_CORE0_SAFE 99 #define PICO_FLASH_ASSUME_CORE0_SAFE 0 100 #endif 101 102 // PICO_CONFIG: PICO_FLASH_ASSUME_CORE1_SAFE, Assume that core 1 will never be accessing flash and so doesn't need to be considered during flash_safe_execute, type=bool, default=0, group=pico_flash 103 #ifndef PICO_FLASH_ASSUME_CORE1_SAFE 104 #define PICO_FLASH_ASSUME_CORE1_SAFE 0 105 #endif 106 107 // PICO_CONFIG: PICO_FLASH_SAFE_EXECUTE_SUPPORT_FREERTOS_SMP, Support using FreeRTOS SMP to make the other core safe during flash_safe_execute, type=bool, default=1 when using FreeRTOS SMP, group=pico_flash 108 #ifndef PICO_FLASH_SAFE_EXECUTE_SUPPORT_FREERTOS_SMP 109 #if LIB_FREERTOS_KERNEL && FREE_RTOS_KERNEL_SMP // set by RP2040 SMP port 110 #define PICO_FLASH_SAFE_EXECUTE_SUPPORT_FREERTOS_SMP 1 111 #endif 112 #endif 113 114 // PICO_CONFIG: PICO_FLASH_SAFE_EXECUTE_PICO_SUPPORT_MULTICORE_LOCKOUT, Support using multicore_lockout functions to make the other core safe during flash_safe_execute, type=bool, default=1 when using pico_multicore, group=pico_flash 115 #ifndef PICO_FLASH_SAFE_EXECUTE_PICO_SUPPORT_MULTICORE_LOCKOUT 116 #if LIB_PICO_MULTICORE 117 #define PICO_FLASH_SAFE_EXECUTE_PICO_SUPPORT_MULTICORE_LOCKOUT 1 118 #endif 119 #endif 120 121 typedef struct { 122 bool (*core_init_deinit)(bool init); 123 int (*enter_safe_zone_timeout_ms)(uint32_t timeout_ms); 124 int (*exit_safe_zone_timeout_ms)(uint32_t timeout_ms); 125 } flash_safety_helper_t; 126 127 /** 128 * Internal method to return the flash safety helper implementation. 129 * \ingroup pico_flash 130 * 131 * Advanced users can provide their own implementation of this function to perform 132 * different inter-core coordination before disabling XIP mode. 133 * 134 * @return the \ref flash_safety_helper_t 135 */ 136 flash_safety_helper_t *get_flash_safety_helper(void); 137 138 #ifdef __cplusplus 139 } 140 #endif 141 142 #endif 143