|
26 | 26 | extern "C" {
|
27 | 27 | #endif
|
28 | 28 |
|
29 |
| -//C This turns on range checking. Is this the value you want to trigger it? |
| 29 | +// This turns on range checking. |
30 | 30 | #ifdef DEBUG_ESP_CORE
|
31 | 31 | #define DEBUG_ESP_MMU
|
32 | 32 | #endif
|
33 | 33 |
|
34 | 34 | #if defined(CORE_MOCK)
|
35 | 35 | #define ets_uart_printf(...) do {} while(false)
|
| 36 | +#define XCHAL_INSTRAM0_VADDR 0x40000000 |
| 37 | +#define XCHAL_INSTRAM1_VADDR 0x40100000 |
| 38 | +#define XCHAL_INSTROM0_VADDR 0x40200000 |
| 39 | +#else |
| 40 | +#include <sys/config.h> // For config/core-isa.h |
| 41 | +/* |
| 42 | + Cautiously use XCHAL_..._VADDR values where possible. |
| 43 | + While XCHAL_..._VADDR values in core-isa.h may define the Xtensa processor |
| 44 | + CONFIG options, they are not always an indication of DRAM, IRAM, or ROM |
| 45 | + size or position in the address space. |
| 46 | +*/ |
36 | 47 | #endif
|
37 | 48 |
|
38 | 49 | /*
|
@@ -71,32 +82,34 @@ DBG_MMU_FLUSH(0)
|
71 | 82 |
|
72 | 83 | static inline __attribute__((always_inline))
|
73 | 84 | bool mmu_is_iram(const void *addr) {
|
74 |
| - #define IRAM_START 0x40100000UL |
| 85 | + const uintptr_t iram_start = (uintptr_t)XCHAL_INSTRAM1_VADDR; |
75 | 86 | #ifndef MMU_IRAM_SIZE
|
76 | 87 | #if defined(__GNUC__) && !defined(CORE_MOCK)
|
77 | 88 | #warning "MMU_IRAM_SIZE was undefined, setting to 0x8000UL!"
|
78 | 89 | #endif
|
79 |
| - #define MMU_IRAM_SIZE 0x8000UL |
| 90 | + #define MMU_IRAM_SIZE 0x8000ul |
80 | 91 | #endif
|
81 |
| - #define IRAM_END (IRAM_START + MMU_IRAM_SIZE) |
| 92 | + const uintptr_t iram_end = iram_start + MMU_IRAM_SIZE; |
82 | 93 |
|
83 |
| - return (IRAM_START <= (uintptr_t)addr && IRAM_END > (uintptr_t)addr); |
| 94 | + return (iram_start <= (uintptr_t)addr && iram_end > (uintptr_t)addr); |
84 | 95 | }
|
85 | 96 |
|
86 | 97 | static inline __attribute__((always_inline))
|
87 | 98 | bool mmu_is_dram(const void *addr) {
|
88 |
| - #define DRAM_START 0x3FF80000UL |
89 |
| - #define DRAM_END 0x40000000UL |
| 99 | + const uintptr_t dram_start = 0x3FFE8000ul; |
| 100 | + // The start of the Boot ROM sits at the end of DRAM. 0x40000000ul; |
| 101 | + const uintptr_t dram_end = (uintptr_t)XCHAL_INSTRAM0_VADDR; |
90 | 102 |
|
91 |
| - return (DRAM_START <= (uintptr_t)addr && DRAM_END > (uintptr_t)addr); |
| 103 | + return (dram_start <= (uintptr_t)addr && dram_end > (uintptr_t)addr); |
92 | 104 | }
|
93 | 105 |
|
94 | 106 | static inline __attribute__((always_inline))
|
95 | 107 | bool mmu_is_icache(const void *addr) {
|
96 |
| - #define ICACHE_START 0x40200000UL |
97 |
| - #define ICACHE_END (ICACHE_START + 0x100000UL) |
| 108 | + extern void _irom0_text_end(void); |
| 109 | + const uintptr_t icache_start = (uintptr_t)XCHAL_INSTROM0_VADDR; |
| 110 | + const uintptr_t icache_end = (uintptr_t)_irom0_text_end; |
98 | 111 |
|
99 |
| - return (ICACHE_START <= (uintptr_t)addr && ICACHE_END > (uintptr_t)addr); |
| 112 | + return (icache_start <= (uintptr_t)addr && icache_end > (uintptr_t)addr); |
100 | 113 | }
|
101 | 114 |
|
102 | 115 | #ifdef DEBUG_ESP_MMU
|
@@ -127,90 +140,131 @@ bool mmu_is_icache(const void *addr) {
|
127 | 140 | static inline __attribute__((always_inline))
|
128 | 141 | uint8_t mmu_get_uint8(const void *p8) {
|
129 | 142 | ASSERT_RANGE_TEST_READ(p8);
|
130 |
| - uint32_t val = (*(uint32_t *)((uintptr_t)p8 & ~0x3)); |
131 |
| - uint32_t pos = ((uintptr_t)p8 & 0x3) * 8; |
| 143 | + // https://gist.github.com/shafik/848ae25ee209f698763cffee272a58f8#how-do-we-type-pun-correctly |
| 144 | + // Comply with strict-aliasing rules. Using memcpy is a Standards suggested |
| 145 | + // method for type punning. The compiler optimizer will replace the memcpy |
| 146 | + // with an `l32i` instruction. Using __builtin_memcpy to ensure we get the |
| 147 | + // effects of the compiler optimization and not some #define version of |
| 148 | + // memcpy. |
| 149 | + void *v32 = (void *)((uintptr_t)p8 & ~(uintptr_t)3u); |
| 150 | + uint32_t val; |
| 151 | + __builtin_memcpy(&val, v32, sizeof(uint32_t)); |
| 152 | + // Use an empty ASM to reference the 32-bit value. This will block the |
| 153 | + // compiler from immediately optimizing to an 8-bit or 16-bit load instruction |
| 154 | + // against IRAM memory. (This approach was inspired by |
| 155 | + // https://github.com/esp8266/Arduino/pull/7780#discussion_r548303374) |
| 156 | + // This issue was seen when using a constant address with the GCC 10.3 |
| 157 | + // compiler. |
| 158 | + // As a general practice, I think referencing by way of Extended ASM R/W |
| 159 | + // output register will stop the the compiler from reloading the value later |
| 160 | + // as 8-bit load from IRAM. |
| 161 | + asm volatile ("" :"+r"(val)); // inject 32-bit dependency |
| 162 | + uint32_t pos = ((uintptr_t)p8 & 3u) * 8u; |
132 | 163 | val >>= pos;
|
133 | 164 | return (uint8_t)val;
|
134 | 165 | }
|
135 | 166 |
|
136 | 167 | static inline __attribute__((always_inline))
|
137 | 168 | uint16_t mmu_get_uint16(const uint16_t *p16) {
|
138 | 169 | ASSERT_RANGE_TEST_READ(p16);
|
139 |
| - uint32_t val = (*(uint32_t *)((uintptr_t)p16 & ~0x3)); |
140 |
| - uint32_t pos = ((uintptr_t)p16 & 0x3) * 8; |
| 170 | + void *v32 = (void *)((uintptr_t)p16 & ~(uintptr_t)0x3u); |
| 171 | + uint32_t val; |
| 172 | + __builtin_memcpy(&val, v32, sizeof(uint32_t)); |
| 173 | + asm volatile ("" :"+r"(val)); |
| 174 | + uint32_t pos = ((uintptr_t)p16 & 3u) * 8u; |
141 | 175 | val >>= pos;
|
142 | 176 | return (uint16_t)val;
|
143 | 177 | }
|
144 | 178 |
|
145 | 179 | static inline __attribute__((always_inline))
|
146 | 180 | int16_t mmu_get_int16(const int16_t *p16) {
|
147 | 181 | ASSERT_RANGE_TEST_READ(p16);
|
148 |
| - uint32_t val = (*(uint32_t *)((uintptr_t)p16 & ~0x3)); |
149 |
| - uint32_t pos = ((uintptr_t)p16 & 0x3) * 8; |
| 182 | + void *v32 = (void *)((uintptr_t)p16 & ~(uintptr_t)3u); |
| 183 | + uint32_t val; |
| 184 | + __builtin_memcpy(&val, v32, sizeof(uint32_t)); |
| 185 | + asm volatile ("" :"+r"(val)); |
| 186 | + uint32_t pos = ((uintptr_t)p16 & 3u) * 8u; |
150 | 187 | val >>= pos;
|
151 | 188 | return (int16_t)val;
|
152 | 189 | }
|
153 | 190 |
|
154 | 191 | static inline __attribute__((always_inline))
|
155 | 192 | uint8_t mmu_set_uint8(void *p8, const uint8_t val) {
|
156 | 193 | ASSERT_RANGE_TEST_WRITE(p8);
|
157 |
| - uint32_t pos = ((uintptr_t)p8 & 0x3) * 8; |
| 194 | + uint32_t pos = ((uintptr_t)p8 & 3u) * 8u; |
158 | 195 | uint32_t sval = val << pos;
|
159 |
| - uint32_t valmask = 0x0FF << pos; |
| 196 | + uint32_t valmask = 0x0FFu << pos; |
| 197 | + |
| 198 | + void *v32 = (void *)((uintptr_t)p8 & ~(uintptr_t)3u); |
| 199 | + uint32_t ival; |
| 200 | + __builtin_memcpy(&ival, v32, sizeof(uint32_t)); |
| 201 | + asm volatile ("" :"+r"(ival)); |
160 | 202 |
|
161 |
| - uint32_t *p32 = (uint32_t *)((uintptr_t)p8 & ~0x3); |
162 |
| - uint32_t ival = *p32; |
163 | 203 | ival &= (~valmask);
|
164 | 204 | ival |= sval;
|
165 |
| - *p32 = ival; |
| 205 | + /* |
| 206 | + This 32-bit dependency injection does not appear to be needed with the |
| 207 | + current GCC 10.3; however, that could change in the future versions. Or, I |
| 208 | + may not have the right test for it to fail. |
| 209 | + */ |
| 210 | + asm volatile ("" :"+r"(ival)); |
| 211 | + __builtin_memcpy(v32, &ival, sizeof(uint32_t)); |
166 | 212 | return val;
|
167 | 213 | }
|
168 | 214 |
|
169 | 215 | static inline __attribute__((always_inline))
|
170 | 216 | uint16_t mmu_set_uint16(uint16_t *p16, const uint16_t val) {
|
171 | 217 | ASSERT_RANGE_TEST_WRITE(p16);
|
172 |
| - uint32_t pos = ((uintptr_t)p16 & 0x3) * 8; |
| 218 | + uint32_t pos = ((uintptr_t)p16 & 3u) * 8u; |
173 | 219 | uint32_t sval = val << pos;
|
174 |
| - uint32_t valmask = 0x0FFFF << pos; |
| 220 | + uint32_t valmask = 0x0FFFFu << pos; |
| 221 | + |
| 222 | + void *v32 = (void *)((uintptr_t)p16 & ~(uintptr_t)3u); |
| 223 | + uint32_t ival; |
| 224 | + __builtin_memcpy(&ival, v32, sizeof(uint32_t)); |
| 225 | + asm volatile ("" :"+r"(ival)); |
175 | 226 |
|
176 |
| - uint32_t *p32 = (uint32_t *)((uintptr_t)p16 & ~0x3); |
177 |
| - uint32_t ival = *p32; |
178 | 227 | ival &= (~valmask);
|
179 | 228 | ival |= sval;
|
180 |
| - *p32 = ival; |
| 229 | + asm volatile ("" :"+r"(ival)); |
| 230 | + __builtin_memcpy(v32, &ival, sizeof(uint32_t)); |
181 | 231 | return val;
|
182 | 232 | }
|
183 | 233 |
|
184 | 234 | static inline __attribute__((always_inline))
|
185 | 235 | int16_t mmu_set_int16(int16_t *p16, const int16_t val) {
|
186 | 236 | ASSERT_RANGE_TEST_WRITE(p16);
|
187 | 237 | uint32_t sval = (uint16_t)val;
|
188 |
| - uint32_t pos = ((uintptr_t)p16 & 0x3) * 8; |
| 238 | + uint32_t pos = ((uintptr_t)p16 & 3u) * 8u; |
189 | 239 | sval <<= pos;
|
190 |
| - uint32_t valmask = 0x0FFFF << pos; |
| 240 | + uint32_t valmask = 0x0FFFFu << pos; |
| 241 | + |
| 242 | + void *v32 = (void *)((uintptr_t)p16 & ~(uintptr_t)3u); |
| 243 | + uint32_t ival; |
| 244 | + __builtin_memcpy(&ival, v32, sizeof(uint32_t)); |
| 245 | + asm volatile ("" :"+r"(ival)); |
191 | 246 |
|
192 |
| - uint32_t *p32 = (uint32_t *)((uintptr_t)p16 & ~0x3); |
193 |
| - uint32_t ival = *p32; |
194 | 247 | ival &= (~valmask);
|
195 | 248 | ival |= sval;
|
196 |
| - *p32 = ival; |
| 249 | + asm volatile ("" :"+r"(ival)); |
| 250 | + __builtin_memcpy(v32, &ival, sizeof(uint32_t)); |
197 | 251 | return val;
|
198 | 252 | }
|
199 | 253 |
|
200 | 254 | #if (MMU_IRAM_SIZE > 32*1024) && !defined(MMU_SEC_HEAP)
|
201 |
| -extern void _text_end(void); |
202 | 255 | #define MMU_SEC_HEAP mmu_sec_heap()
|
203 | 256 | #define MMU_SEC_HEAP_SIZE mmu_sec_heap_size()
|
204 | 257 |
|
205 | 258 | static inline __attribute__((always_inline))
|
206 | 259 | void *mmu_sec_heap(void) {
|
207 |
| - uint32_t sec_heap = (uint32_t)_text_end + 32; |
208 |
| - return (void *)(sec_heap &= ~7); |
| 260 | + extern void _text_end(void); |
| 261 | + uintptr_t sec_heap = (uintptr_t)_text_end + (uintptr_t)32u; |
| 262 | + return (void *)(sec_heap &= ~(uintptr_t)7u); |
209 | 263 | }
|
210 | 264 |
|
211 | 265 | static inline __attribute__((always_inline))
|
212 | 266 | size_t mmu_sec_heap_size(void) {
|
213 |
| - return (size_t)0xC000UL - ((size_t)mmu_sec_heap() - 0x40100000UL); |
| 267 | + return (size_t)0xC000ul - ((uintptr_t)mmu_sec_heap() - (uintptr_t)XCHAL_INSTRAM1_VADDR); |
214 | 268 | }
|
215 | 269 | #endif
|
216 | 270 |
|
|
0 commit comments