MemoryPool Redux: works! ahbmalloc has been deprecated and will be removed soon.
[clinton/Smoothieware.git] / build / mbed_custom.cpp
1 /* Copyright 2013 Adam Green (http://mbed.org/users/AdamGreen/)
2
3 Licensed under the Apache License, Version 2.0 (the "License");
4 you may not use this file except in compliance with the License.
5 You may obtain a copy of the License at
6
7 http://www.apache.org/licenses/LICENSE-2.0
8
9 Unless required by applicable law or agreed to in writing, software
10 distributed under the License is distributed on an "AS IS" BASIS,
11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 See the License for the specific language governing permissions and
13 limitations under the License.
14 */
15 /* Provide routines which hook the MRI debug monitor into GCC4MBED projects. */
16 #include <string.h>
17 #include <sys/types.h>
18 #include <errno.h>
19 #include <mri.h>
20 #include <cmsis.h>
21 #include "mpu.h"
22
23 #include "platform_memory.h"
24
25 unsigned int g_maximumHeapAddress;
26
27 static void fillUnusedRAM(void);
28 static void configureStackSizeLimit(unsigned int stackSizeLimit);
29 static unsigned int alignTo32Bytes(unsigned int value);
30 static void configureMpuToCatchStackOverflowIntoHeap(unsigned int maximumHeapAddress);
31 static void configureMpuRegionToAccessAllMemoryWithNoCaching(void);
32
33
34 /* Symbols exposed from the linker script. */
35 extern unsigned int __bss_start__;
36 extern unsigned int __bss_end__;
37 extern unsigned int __StackTop;
38 extern "C" unsigned int __end__;
39
40 extern "C" int main(void);
41 extern "C" void __libc_init_array(void);
42 // extern "C" void exit(int ErrorCode);
43 extern "C" void _start(void)
44 {
45 int bssSize = (int)&__bss_end__ - (int)&__bss_start__;
46 int mainReturnValue;
47
48 memset(&__bss_start__, 0, bssSize);
49 fillUnusedRAM();
50
51 if (STACK_SIZE)
52 {
53 configureStackSizeLimit(STACK_SIZE);
54 }
55 if (WRITE_BUFFER_DISABLE)
56 {
57 disableMPU();
58 configureMpuRegionToAccessAllMemoryWithNoCaching();
59 enableMPU();
60 }
61 if (MRI_ENABLE)
62 {
63 __mriInit(MRI_INIT_PARAMETERS);
64 if (MRI_BREAK_ON_INIT)
65 __debugbreak();
66 }
67
68 // MemoryPool stuff - needs to be initialised before __libc_init_array
69 // so static ctors can use them
70 extern uint8_t __AHB0_dyn_start;
71 extern uint8_t __AHB0_end;
72 extern uint8_t __AHB1_dyn_start;
73 extern uint8_t __AHB1_end;
74
75 MemoryPool _AHB0_stack(&__AHB0_dyn_start, &__AHB0_end - &__AHB0_dyn_start);
76 MemoryPool _AHB1_stack(&__AHB1_dyn_start, &__AHB1_end - &__AHB1_dyn_start);
77
78 _AHB0 = &_AHB0_stack;
79 _AHB1 = &_AHB1_stack;
80 // MemoryPool init done
81
82 __libc_init_array();
83 mainReturnValue = main();
84 exit(mainReturnValue);
85 }
86
87 static __attribute__((naked)) void fillUnusedRAM(void)
88 {
89 __asm (
90 ".syntax unified\n"
91 ".thumb\n"
92 // Fill 2 words (8 bytes) at a time with 0xdeadbeef.
93 " ldr r2, =__FillStart\n"
94 " movw r0, #0xbeef\n"
95 " movt r0, #0xdead\n"
96 " mov r1, r0\n"
97 // Don't fill past current stack pointer value.
98 " mov r3, sp\n"
99 " bics r3, r3, #7\n"
100 "1$:\n"
101 " strd r0, r1, [r2], #8\n"
102 " cmp r2, r3\n"
103 " blo 1$\n"
104 " bx lr\n"
105 );
106 }
107
108 static void configureStackSizeLimit(unsigned int stackSizeLimit)
109 {
110 // Note: 32 bytes are reserved to fall between top of heap and top of stack for minimum MPU guard region.
111 g_maximumHeapAddress = alignTo32Bytes((unsigned int)&__StackTop - stackSizeLimit - 32);
112 configureMpuToCatchStackOverflowIntoHeap(g_maximumHeapAddress);
113 }
114
115 static unsigned int alignTo32Bytes(unsigned int value)
116 {
117 return (value + 31) & ~31;
118 }
119
120 static void configureMpuToCatchStackOverflowIntoHeap(unsigned int maximumHeapAddress)
121 {
122 #define MPU_REGION_SIZE_OF_32_BYTES ((5-1) << MPU_RASR_SIZE_SHIFT) // 2^5 = 32 bytes.
123
124 prepareToAccessMPURegion(getHighestMPUDataRegionIndex());
125 setMPURegionAddress(maximumHeapAddress);
126 setMPURegionAttributeAndSize(MPU_REGION_SIZE_OF_32_BYTES | MPU_RASR_ENABLE);
127 enableMPUWithDefaultMemoryMap();
128 }
129
130 static void configureMpuRegionToAccessAllMemoryWithNoCaching(void)
131 {
132 static const uint32_t regionToStartAtAddress0 = 0U;
133 static const uint32_t regionReadWrite = 1 << MPU_RASR_AP_SHIFT;
134 static const uint32_t regionSizeAt4GB = 31 << MPU_RASR_SIZE_SHIFT; /* 4GB = 2^(31+1) */
135 static const uint32_t regionEnable = MPU_RASR_ENABLE;
136 static const uint32_t regionSizeAndAttributes = regionReadWrite | regionSizeAt4GB | regionEnable;
137 uint32_t regionIndex = STACK_SIZE ? getHighestMPUDataRegionIndex() - 1 : getHighestMPUDataRegionIndex();
138
139 prepareToAccessMPURegion(regionIndex);
140 setMPURegionAddress(regionToStartAtAddress0);
141 setMPURegionAttributeAndSize(regionSizeAndAttributes);
142 }
143
144
145 extern "C" int __real__read(int file, char *ptr, int len);
146 extern "C" int __wrap__read(int file, char *ptr, int len)
147 {
148 if (MRI_SEMIHOST_STDIO && file < 3)
149 return __mriNewlib_SemihostRead(file, ptr, len);
150 return __real__read(file, ptr, len);
151 }
152
153
154 extern "C" int __real__write(int file, char *ptr, int len);
155 extern "C" int __wrap__write(int file, char *ptr, int len)
156 {
157 if (MRI_SEMIHOST_STDIO && file < 3)
158 return __mriNewlib_SemihostWrite(file, ptr, len);
159 return __real__write(file, ptr, len);
160 }
161
162
163 extern "C" int __real__isatty(int file);
164 extern "C" int __wrap__isatty(int file)
165 {
166 /* Hardcoding the stdin/stdout/stderr handles to be interactive tty devices, unlike mbed.ar */
167 if (file < 3)
168 return 1;
169 return __real__isatty(file);
170 }
171
172
173 extern "C" int __wrap_semihost_connected(void)
174 {
175 /* MRI makes it look like there is no mbed interface attached since it disables the JTAG portion but MRI does
176 support some of the mbed semihost calls when it is running so force it to return -1, indicating that the
177 interface is attached. */
178 return -1;
179 }
180
181
182
183 extern "C" void abort(void)
184 {
185 if (MRI_ENABLE)
186 __debugbreak();
187
188 exit(1);
189 }
190
191
192 extern "C" void __cxa_pure_virtual(void)
193 {
194 abort();
195 }
196
197
198 /* Trap calls to malloc/free/realloc in ISR. */
199 extern "C" void __malloc_lock(void)
200 {
201 if (__get_IPSR() != 0)
202 __debugbreak();
203 }
204
205 extern "C" void __malloc_unlock(void)
206 {
207 }
208
209
210 /* Turn off the errno macro and use actual external global variable instead. */
211 #undef errno
212 extern int errno;
213
214 static int doesHeapCollideWithStack(unsigned int newHeap);
215
216 /* Dynamic memory allocation related syscalls. */
217 extern "C" caddr_t _sbrk(int incr)
218 {
219 static unsigned char* heap = (unsigned char*)&__end__;
220 unsigned char* prev_heap = heap;
221 unsigned char* new_heap = heap + incr;
222
223 if (doesHeapCollideWithStack((unsigned int)new_heap))
224 {
225 errno = ENOMEM;
226 return (caddr_t)-1;
227 }
228
229 heap = new_heap;
230 return (caddr_t) prev_heap;
231 }
232
233 static int doesHeapCollideWithStack(unsigned int newHeap)
234 {
235 return ((newHeap >= __get_MSP()) ||
236 (STACK_SIZE && newHeap >= g_maximumHeapAddress));
237 }
238
239
240 /* Optional functionality which will tag each heap allocation with the caller's return address. */
241 #ifdef HEAP_TAGS
242
243 const unsigned int* __smoothieHeapBase = &__end__;
244
245 extern "C" void* __real_malloc(size_t size);
246 extern "C" void* __real_realloc(void* ptr, size_t size);
247 extern "C" void __real_free(void* ptr);
248
249 static void setTag(void* pv, unsigned int tag);
250 static unsigned int* footerForChunk(void* pv);
251 static unsigned int* headerForChunk(void* pv);
252 static unsigned int sizeOfChunk(unsigned int* pHeader);
253 static int isChunkInUse(void* pv);
254
255 extern "C" __attribute__((naked)) void __wrap_malloc(size_t size)
256 {
257 __asm (
258 ".syntax unified\n"
259 ".thumb\n"
260 "mov r1,lr\n"
261 "b mallocWithTag\n"
262 );
263 }
264
265 extern "C" void* mallocWithTag(size_t size, unsigned int tag)
266 {
267 void* p = __real_malloc(size + sizeof(tag));
268 if (!p && __smoothieHeapBase)
269 return p;
270 setTag(p, tag);
271 return p;
272 }
273
274 static void setTag(void* pv, unsigned int tag)
275 {
276 unsigned int* pFooter = footerForChunk(pv);
277 *pFooter = tag;
278 }
279
280 static unsigned int* footerForChunk(void* pv)
281 {
282 unsigned int* pHeader = headerForChunk(pv);
283 unsigned int size = sizeOfChunk(pHeader);
284 return (unsigned int*)(void*)((char*)pHeader + size);
285 }
286
287 static unsigned int* headerForChunk(void* pv)
288 {
289 // Header is allocated two words (8 bytes) before the publicly returned allocation chunk address.
290 unsigned int* p = (unsigned int*)pv;
291 return &p[-2];
292 }
293
294 static unsigned int sizeOfChunk(unsigned int* pHeader)
295 {
296 /* Remove previous chunk in use flag. */
297 return pHeader[1] & ~1;
298 }
299
300 extern "C" __attribute__((naked)) void __wrap_realloc(void* ptr, size_t size)
301 {
302 __asm (
303 ".syntax unified\n"
304 ".thumb\n"
305 "mov r2,lr\n"
306 "b reallocWithTag\n"
307 );
308 }
309
310 extern "C" void* reallocWithTag(void* ptr, size_t size, unsigned int tag)
311 {
312 void* p = __real_realloc(ptr, size + sizeof(tag));
313 if (!p)
314 return p;
315 setTag(p, tag);
316 return p;
317 }
318
319 extern "C" void __wrap_free(void* ptr)
320 {
321 if (!isChunkInUse(ptr))
322 __debugbreak();
323 __real_free(ptr);
324 }
325
326 static int isChunkInUse(void* pv)
327 {
328 unsigned int* pFooter = footerForChunk(pv);
329 return pFooter[1] & 1;
330 }
331
332 __attribute__((naked)) void* operator new(size_t size)
333 {
334 __asm (
335 ".syntax unified\n"
336 ".thumb\n"
337 "push {r4,lr}\n"
338 "mov r1,lr\n"
339 "bl mallocWithTag\n"
340 "cbnz r0, 1$\n"
341 "bl abort\n"
342 "1$:\n"
343 "pop {r4,pc}\n"
344 );
345 // This line never executes but silences no return value warning from compiler.
346 return (void*)1;
347 }
348
349 #else
350
351 /* Wrap memory allocation routines to make sure that they aren't being called from interrupt handler. */
352 static void breakOnHeapOpFromInterruptHandler(void)
353 {
354 if (__get_IPSR() != 0)
355 __debugbreak();
356 }
357
358 extern "C" void* __real_malloc(size_t size);
359 extern "C" void* __wrap_malloc(size_t size)
360 {
361 breakOnHeapOpFromInterruptHandler();
362 return __real_malloc(size);
363 }
364
365
366 extern "C" void* __real_realloc(void* ptr, size_t size);
367 extern "C" void* __wrap_realloc(void* ptr, size_t size)
368 {
369 breakOnHeapOpFromInterruptHandler();
370 return __real_realloc(ptr, size);
371 }
372
373
374 extern "C" void __real_free(void* ptr);
375 extern "C" void __wrap_free(void* ptr)
376 {
377 breakOnHeapOpFromInterruptHandler();
378 __real_free(ptr);
379 }
380
381 #endif // HEAP_TAGS