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