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