1 /*
2 * SPDX-FileCopyrightText: 2010-2021 Espressif Systems (Shanghai) CO LTD
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #pragma once
8 #include <stdlib.h>
9 #include <stdint.h>
10 #include <stdbool.h>
11
12 #include "soc/soc.h"
13 #include "soc/soc_caps.h"
14 #include "sdkconfig.h"
15 #include "esp_attr.h"
16
17 #ifdef __cplusplus
18 extern "C" {
19 #endif
20
21 /** Common functions, to be kept in sync with bootloader_memory_utils.h **/
22
23 /**
24 * @brief Check if the IRAM and DRAM are separate or using the same memory space
25 *
26 * @return true if the DRAM and IRAM are sharing the same memory space, false otherwise
27 */
28 __attribute__((always_inline))
esp_dram_match_iram(void)29 inline static bool esp_dram_match_iram(void) {
30 return (SOC_DRAM_LOW == SOC_IRAM_LOW && SOC_DRAM_HIGH == SOC_IRAM_HIGH);
31 }
32
33 /**
34 * @brief Check if the pointer is in iram
35 *
36 * @param p pointer
37 *
38 * @return true: is in iram; false: not in iram
39 */
40 __attribute__((always_inline))
esp_ptr_in_iram(const void * p)41 inline static bool esp_ptr_in_iram(const void *p) {
42 #if CONFIG_IDF_TARGET_ESP32 && CONFIG_FREERTOS_UNICORE
43 return ((intptr_t)p >= SOC_CACHE_APP_LOW && (intptr_t)p < SOC_IRAM_HIGH);
44 #else
45 return ((intptr_t)p >= SOC_IRAM_LOW && (intptr_t)p < SOC_IRAM_HIGH);
46 #endif
47 }
48
49 /**
50 * @brief Check if the pointer is in dram
51 *
52 * @param p pointer
53 *
54 * @return true: is in dram; false: not in dram
55 */
56 __attribute__((always_inline))
esp_ptr_in_dram(const void * p)57 inline static bool esp_ptr_in_dram(const void *p) {
58 return ((intptr_t)p >= SOC_DRAM_LOW && (intptr_t)p < SOC_DRAM_HIGH);
59 }
60
61 /**
62 * @brief Check if the pointer is in diram_dram
63 *
64 * @param p pointer
65 *
66 * @return true: is in diram_dram; false: not in diram_dram
67 */
68 __attribute__((always_inline))
esp_ptr_in_diram_dram(const void * p)69 inline static bool esp_ptr_in_diram_dram(const void *p) {
70 return ((intptr_t)p >= SOC_DIRAM_DRAM_LOW && (intptr_t)p < SOC_DIRAM_DRAM_HIGH);
71 }
72
73 /**
74 * @brief Check if the pointer is in diram_iram
75 *
76 * @param p pointer
77 *
78 * @return true: is in diram_iram; false: not in diram_iram
79 */
80 __attribute__((always_inline))
esp_ptr_in_diram_iram(const void * p)81 inline static bool esp_ptr_in_diram_iram(const void *p) {
82 // TODO: IDF-5980 esp32c6 D/I RAM share the same address
83 #if SOC_DIRAM_IRAM_LOW == SOC_DIRAM_DRAM_LOW
84 return false;
85 #else
86 return ((intptr_t)p >= SOC_DIRAM_IRAM_LOW && (intptr_t)p < SOC_DIRAM_IRAM_HIGH);
87 #endif
88 }
89
90 /**
91 * @brief Check if the pointer is in rtc_iram_fast
92 *
93 * @param p pointer
94 *
95 * @return true: is in rtc_iram_fast; false: not in rtc_iram_fast
96 */
97 __attribute__((always_inline))
esp_ptr_in_rtc_iram_fast(const void * p)98 inline static bool esp_ptr_in_rtc_iram_fast(const void *p) {
99 #if SOC_RTC_FAST_MEM_SUPPORTED
100 return ((intptr_t)p >= SOC_RTC_IRAM_LOW && (intptr_t)p < SOC_RTC_IRAM_HIGH);
101 #else
102 return false;
103 #endif
104 }
105
106 /**
107 * @brief Check if the pointer is in rtc_dram_fast
108 *
109 * @param p pointer
110 *
111 * @return true: is in rtc_dram_fast; false: not in rtc_dram_fast
112 */
113 __attribute__((always_inline))
esp_ptr_in_rtc_dram_fast(const void * p)114 inline static bool esp_ptr_in_rtc_dram_fast(const void *p) {
115 #if SOC_RTC_FAST_MEM_SUPPORTED
116 return ((intptr_t)p >= SOC_RTC_DRAM_LOW && (intptr_t)p < SOC_RTC_DRAM_HIGH);
117 #else
118 return false;
119 #endif
120 }
121
122 /**
123 * @brief Check if the pointer is in rtc_slow
124 *
125 * @param p pointer
126 *
127 * @return true: is in rtc_slow; false: not in rtc_slow
128 */
129 __attribute__((always_inline))
esp_ptr_in_rtc_slow(const void * p)130 inline static bool esp_ptr_in_rtc_slow(const void *p) {
131 #if SOC_RTC_SLOW_MEM_SUPPORTED
132 return ((intptr_t)p >= SOC_RTC_DATA_LOW && (intptr_t)p < SOC_RTC_DATA_HIGH);
133 #else
134 return false;
135 #endif
136 }
137
138
139 /* Convert a D/IRAM DRAM pointer to equivalent word address in IRAM
140
141 - Address must be word aligned
142 - Address must pass esp_ptr_in_diram_dram() test, or result will be invalid pointer
143 */
144 __attribute__((always_inline))
esp_ptr_diram_dram_to_iram(const void * p)145 inline static void * esp_ptr_diram_dram_to_iram(const void *p) {
146 #if SOC_DIRAM_INVERTED
147 return (void *) ( SOC_DIRAM_IRAM_LOW + (SOC_DIRAM_DRAM_HIGH - (intptr_t)p) - 4);
148 #else
149 return (void *) ( SOC_DIRAM_IRAM_LOW + ((intptr_t)p - SOC_DIRAM_DRAM_LOW) );
150 #endif
151 }
152
153 /* Convert a D/IRAM IRAM pointer to equivalent word address in DRAM
154
155 - Address must be word aligned
156 - Address must pass esp_ptr_in_diram_iram() test, or result will be invalid pointer
157 */
158 __attribute__((always_inline))
esp_ptr_diram_iram_to_dram(const void * p)159 inline static void * esp_ptr_diram_iram_to_dram(const void *p) {
160 #if SOC_DIRAM_INVERTED
161 return (void *) ( SOC_DIRAM_DRAM_LOW + (SOC_DIRAM_IRAM_HIGH - (intptr_t)p) - 4);
162 #else
163 return (void *) ( SOC_DIRAM_DRAM_LOW + ((intptr_t)p - SOC_DIRAM_IRAM_LOW) );
164 #endif
165 }
166
167 /** End of common functions to be kept in sync with bootloader_memory_utils.h **/
168 /** Add app-specific functions below **/
169
170 /**
171 * @brief Check if the pointer is dma capable
172 *
173 * @param p pointer
174 *
175 * @return true: capable; false: not capable
176 */
177 __attribute__((always_inline))
esp_ptr_dma_capable(const void * p)178 inline static bool esp_ptr_dma_capable(const void *p)
179 {
180 return (intptr_t)p >= SOC_DMA_LOW && (intptr_t)p < SOC_DMA_HIGH;
181 }
182
183 /**
184 * @brief Check if the pointer is in external ram dma capable region
185 *
186 * @param p pointer
187 *
188 * @return true: capable; false: not capable
189 */
190 bool esp_ptr_dma_ext_capable(const void *p);
191
192 /**
193 * @brief Check if the pointer is word aligned
194 *
195 * @param p pointer
196 *
197 * @return true: aligned; false: not aligned
198 */
199 __attribute__((always_inline))
esp_ptr_word_aligned(const void * p)200 inline static bool esp_ptr_word_aligned(const void *p)
201 {
202 return ((intptr_t)p) % 4 == 0;
203 }
204
205 /**
206 * @brief Check if the pointer is executable
207 *
208 * @param p pointer
209 *
210 * @return true: is executable; false: not executable
211 */
212 __attribute__((always_inline))
esp_ptr_executable(const void * p)213 inline static bool esp_ptr_executable(const void *p)
214 {
215 intptr_t ip = (intptr_t) p;
216 return (ip >= SOC_IROM_LOW && ip < SOC_IROM_HIGH)
217 || (ip >= SOC_IRAM_LOW && ip < SOC_IRAM_HIGH)
218 || (ip >= SOC_IROM_MASK_LOW && ip < SOC_IROM_MASK_HIGH)
219 #if defined(SOC_CACHE_APP_LOW) && defined(CONFIG_FREERTOS_UNICORE)
220 || (ip >= SOC_CACHE_APP_LOW && ip < SOC_CACHE_APP_HIGH)
221 #endif
222 #if SOC_RTC_FAST_MEM_SUPPORTED
223 || (ip >= SOC_RTC_IRAM_LOW && ip < SOC_RTC_IRAM_HIGH)
224 #endif
225 ;
226 }
227
228 /**
229 * @brief Check if the pointer is byte accessible
230 *
231 * @param p pointer
232 *
233 * @return true: is byte accessible; false: not byte accessible
234 */
235 bool esp_ptr_byte_accessible(const void *p);
236
237 /**
238 * @brief Check if the pointer is in internal ram
239 *
240 * @param p pointer
241 *
242 * @return true: is in internal ram; false: not in internal ram
243 */
244 __attribute__((always_inline))
esp_ptr_internal(const void * p)245 inline static bool esp_ptr_internal(const void *p) {
246 bool r;
247 r = ((intptr_t)p >= SOC_MEM_INTERNAL_LOW && (intptr_t)p < SOC_MEM_INTERNAL_HIGH);
248
249 #if SOC_RTC_SLOW_MEM_SUPPORTED
250 r |= ((intptr_t)p >= SOC_RTC_DATA_LOW && (intptr_t)p < SOC_RTC_DATA_HIGH);
251 #endif
252
253 #if CONFIG_ESP_SYSTEM_ALLOW_RTC_FAST_MEM_AS_HEAP
254 /* For ESP32 case, RTC fast memory is accessible to PRO cpu only and hence
255 * for single core configuration (where it gets added to system heap) following
256 * additional check is required */
257 r |= ((intptr_t)p >= SOC_RTC_DRAM_LOW && (intptr_t)p < SOC_RTC_DRAM_HIGH);
258 #endif
259
260 #if CONFIG_ESP32S3_DATA_CACHE_16KB
261 /* For ESP32-S3, when the DCACHE size is set to 16 kB, the unused 48 kB is
262 * added to the heap in 2 blocks of 32 kB (from 0x3FCF0000) and 16 kB
263 * (from 0x3C000000 (SOC_DROM_LOW) - 0x3C004000).
264 * Though this memory lies in the external memory vaddr, it is no different
265 * from the internal RAM in terms of hardware attributes and it is a part of
266 * the internal RAM when added to the heap.*/
267 r |= ((intptr_t)p >= SOC_DROM_LOW && (intptr_t)p < (SOC_DROM_LOW + 0x4000));
268 #endif
269
270 return r;
271 }
272
273 /**
274 * @brief Check if the pointer is in external ram
275 *
276 * @param p pointer
277 *
278 * @return true: is in external ram; false: not in external ram
279 */
280 bool esp_ptr_external_ram(const void *p);
281
282 /**
283 * @brief Check if the pointer is in drom
284 *
285 * @param p pointer
286 *
287 * @return true: is in drom; false: not in drom
288 */
289 __attribute__((always_inline))
esp_ptr_in_drom(const void * p)290 inline static bool esp_ptr_in_drom(const void *p) {
291 int32_t drom_start_addr = SOC_DROM_LOW;
292 #if CONFIG_ESP32S3_DATA_CACHE_16KB
293 /* For ESP32-S3, when the DCACHE size is set to 16 kB, the unused 48 kB is
294 * added to the heap in 2 blocks of 32 kB (from 0x3FCF0000) and 16 kB
295 * (from 0x3C000000 (SOC_DROM_LOW) - 0x3C004000).
296 * The drom_start_addr has to be moved by 0x4000 (16kB) to accomodate
297 * this addition. */
298 drom_start_addr += 0x4000;
299 #endif
300
301 return ((intptr_t)p >= drom_start_addr && (intptr_t)p < SOC_DROM_HIGH);
302 }
303
304 /**
305 * @brief Check if the stack pointer is in dram
306 *
307 * @param sp stack pointer
308 *
309 * @return true: is in dram; false: not in dram
310 */
311 __attribute__((always_inline))
esp_stack_ptr_in_dram(uint32_t sp)312 inline static bool esp_stack_ptr_in_dram(uint32_t sp)
313 {
314 //Check if stack ptr is in between SOC_DRAM_LOW and SOC_DRAM_HIGH, and 16 byte aligned.
315 return !(sp < SOC_DRAM_LOW + 0x10 || sp > SOC_DRAM_HIGH - 0x10 || ((sp & 0xF) != 0));
316 }
317
318 #if CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY
319 /**
320 * @brief Check if the stack pointer is in external ram
321 *
322 * @param sp stack pointer
323 *
324 * @return true: is in external ram; false: not in external ram
325 */
326 bool esp_stack_ptr_in_extram(uint32_t sp);
327 #endif
328
329 /**
330 * @brief Check if the stack pointer is sane
331 *
332 * @param sp stack pointer
333 *
334 * @return true: is in sane; false: not in sane
335 */
336 __attribute__((always_inline))
esp_stack_ptr_is_sane(uint32_t sp)337 inline static bool esp_stack_ptr_is_sane(uint32_t sp)
338 {
339 return esp_stack_ptr_in_dram(sp)
340 #if CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY
341 || esp_stack_ptr_in_extram(sp)
342 #endif
343 #if CONFIG_ESP_SYSTEM_ALLOW_RTC_FAST_MEM_AS_HEAP
344 || esp_ptr_in_rtc_dram_fast((void*) sp)
345 #endif
346 ;
347 }
348
349 #ifdef __cplusplus
350 }
351 #endif
352