add mem command to see free ram
[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
24 unsigned int g_maximumHeapAddress;
25
26 static void fillUnusedRAM(void);
27 static void configureStackSizeLimit(unsigned int stackSizeLimit);
28 static unsigned int alignTo32Bytes(unsigned int value);
29 static void configureMpuToCatchStackOverflowIntoHeap(unsigned int maximumHeapAddress);
30 static void configureMpuRegionToAccessAllMemoryWithNoCaching(void);
31
32
33 /* Symbols exposed from the linker script. */
34 extern unsigned int __bss_start__;
35 extern unsigned int __bss_end__;
36 extern unsigned int __StackTop;
37 extern "C" unsigned int __end__;
38
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 __libc_init_array();
69 mainReturnValue = main();
70 exit(mainReturnValue);
71 }
72
73 static __attribute__((naked)) void fillUnusedRAM(void)
74 {
75 __asm (
76 ".syntax unified\n"
77 ".thumb\n"
78 // Fill 2 words (8 bytes) at a time with 0xdeadbeef.
79 " ldr r2, =__FillStart\n"
80 " movw r0, #0xbeef\n"
81 " movt r0, #0xdead\n"
82 " mov r1, r0\n"
83 // Don't fill past current stack pointer value.
84 " mov r3, sp\n"
85 " bics r3, r3, #7\n"
86 "1$:\n"
87 " strd r0, r1, [r2], #8\n"
88 " cmp r2, r3\n"
89 " blo 1$\n"
90 " bx lr\n"
91 );
92 }
93
94 static void configureStackSizeLimit(unsigned int stackSizeLimit)
95 {
96 // Note: 32 bytes are reserved to fall between top of heap and top of stack for minimum MPU guard region.
97 g_maximumHeapAddress = alignTo32Bytes((unsigned int)&__StackTop - stackSizeLimit - 32);
98 configureMpuToCatchStackOverflowIntoHeap(g_maximumHeapAddress);
99 }
100
101 static unsigned int alignTo32Bytes(unsigned int value)
102 {
103 return (value + 31) & ~31;
104 }
105
106 static void configureMpuToCatchStackOverflowIntoHeap(unsigned int maximumHeapAddress)
107 {
108 #define MPU_REGION_SIZE_OF_32_BYTES ((5-1) << MPU_RASR_SIZE_SHIFT) // 2^5 = 32 bytes.
109
110 prepareToAccessMPURegion(getHighestMPUDataRegionIndex());
111 setMPURegionAddress(maximumHeapAddress);
112 setMPURegionAttributeAndSize(MPU_REGION_SIZE_OF_32_BYTES | MPU_RASR_ENABLE);
113 enableMPUWithDefaultMemoryMap();
114 }
115
116 static void configureMpuRegionToAccessAllMemoryWithNoCaching(void)
117 {
118 static const uint32_t regionToStartAtAddress0 = 0U;
119 static const uint32_t regionReadWrite = 1 << MPU_RASR_AP_SHIFT;
120 static const uint32_t regionSizeAt4GB = 31 << MPU_RASR_SIZE_SHIFT; /* 4GB = 2^(31+1) */
121 static const uint32_t regionEnable = MPU_RASR_ENABLE;
122 static const uint32_t regionSizeAndAttributes = regionReadWrite | regionSizeAt4GB | regionEnable;
123 uint32_t regionIndex = STACK_SIZE ? getHighestMPUDataRegionIndex() - 1 : getHighestMPUDataRegionIndex();
124
125 prepareToAccessMPURegion(regionIndex);
126 setMPURegionAddress(regionToStartAtAddress0);
127 setMPURegionAttributeAndSize(regionSizeAndAttributes);
128 }
129
130
131 extern "C" int __real__read(int file, char *ptr, int len);
132 extern "C" int __wrap__read(int file, char *ptr, int len)
133 {
134 if (MRI_SEMIHOST_STDIO && file < 3)
135 return __mriNewlib_SemihostRead(file, ptr, len);
136 return __real__read(file, ptr, len);
137 }
138
139
140 extern "C" int __real__write(int file, char *ptr, int len);
141 extern "C" int __wrap__write(int file, char *ptr, int len)
142 {
143 if (MRI_SEMIHOST_STDIO && file < 3)
144 return __mriNewlib_SemihostWrite(file, ptr, len);
145 return __real__write(file, ptr, len);
146 }
147
148
149 extern "C" int __real__isatty(int file);
150 extern "C" int __wrap__isatty(int file)
151 {
152 /* Hardcoding the stdin/stdout/stderr handles to be interactive tty devices, unlike mbed.ar */
153 if (file < 3)
154 return 1;
155 return __real__isatty(file);
156 }
157
158
159 extern "C" int __wrap_semihost_connected(void)
160 {
161 /* MRI makes it look like there is no mbed interface attached since it disables the JTAG portion but MRI does
162 support some of the mbed semihost calls when it is running so force it to return -1, indicating that the
163 interface is attached. */
164 return -1;
165 }
166
167
168
169 extern "C" void abort(void)
170 {
171 if (MRI_ENABLE)
172 __debugbreak();
173
174 exit(1);
175 }
176
177
178 extern "C" void __cxa_pure_virtual(void)
179 {
180 abort();
181 }
182
183
184 /* Trap calls to malloc/free/realloc in ISR. */
185 extern "C" void __malloc_lock(void)
186 {
187 if (__get_IPSR() != 0)
188 __debugbreak();
189 }
190
191 extern "C" void __malloc_unlock(void)
192 {
193 }
194
195
196 /* Turn off the errno macro and use actual external global variable instead. */
197 #undef errno
198 extern int errno;
199
200 static int doesHeapCollideWithStack(unsigned int newHeap);
201
202 /* Dynamic memory allocation related syscalls. */
203 extern "C" caddr_t _sbrk(int incr)
204 {
205 static unsigned char* heap = (unsigned char*)&__end__;
206 unsigned char* prev_heap = heap;
207 unsigned char* new_heap = heap + incr;
208
209 if (doesHeapCollideWithStack((unsigned int)new_heap))
210 {
211 errno = ENOMEM;
212 return (caddr_t)-1;
213 }
214
215 heap = new_heap;
216 return (caddr_t) prev_heap;
217 }
218
219 static int doesHeapCollideWithStack(unsigned int newHeap)
220 {
221 return ((newHeap >= __get_MSP()) ||
222 (STACK_SIZE && newHeap >= g_maximumHeapAddress));
223 }
224
225
226 /* Optional functionality which will tag each heap allocation with the caller's return address. */
227 #ifdef HEAP_TAGS
228
229 const unsigned int* __smoothieHeapBase = &__end__;
230
231 extern "C" void* __real_malloc(size_t size);
232 extern "C" void* __real_realloc(void* ptr, size_t size);
233 extern "C" void __real_free(void* ptr);
234
235 static void setTag(void* pv, unsigned int tag);
236 static unsigned int* footerForChunk(void* pv);
237 static unsigned int* headerForChunk(void* pv);
238 static unsigned int sizeOfChunk(unsigned int* pHeader);
239 static int isChunkInUse(void* pv);
240
241 extern "C" __attribute__((naked)) void __wrap_malloc(size_t size)
242 {
243 __asm (
244 ".syntax unified\n"
245 ".thumb\n"
246 "mov r1,lr\n"
247 "b mallocWithTag\n"
248 );
249 }
250
251 extern "C" void* mallocWithTag(size_t size, unsigned int tag)
252 {
253 void* p = __real_malloc(size + sizeof(tag));
254 if (!p && __smoothieHeapBase)
255 return p;
256 setTag(p, tag);
257 return p;
258 }
259
260 static void setTag(void* pv, unsigned int tag)
261 {
262 unsigned int* pFooter = footerForChunk(pv);
263 *pFooter = tag;
264 }
265
266 static unsigned int* footerForChunk(void* pv)
267 {
268 unsigned int* pHeader = headerForChunk(pv);
269 unsigned int size = sizeOfChunk(pHeader);
270 return (unsigned int*)(void*)((char*)pHeader + size);
271 }
272
273 static unsigned int* headerForChunk(void* pv)
274 {
275 // Header is allocated two words (8 bytes) before the publicly returned allocation chunk address.
276 unsigned int* p = (unsigned int*)pv;
277 return &p[-2];
278 }
279
280 static unsigned int sizeOfChunk(unsigned int* pHeader)
281 {
282 /* Remove previous chunk in use flag. */
283 return pHeader[1] & ~1;
284 }
285
286 extern "C" __attribute__((naked)) void __wrap_realloc(void* ptr, size_t size)
287 {
288 __asm (
289 ".syntax unified\n"
290 ".thumb\n"
291 "mov r2,lr\n"
292 "b reallocWithTag\n"
293 );
294 }
295
296 extern "C" void* reallocWithTag(void* ptr, size_t size, unsigned int tag)
297 {
298 void* p = __real_realloc(ptr, size + sizeof(tag));
299 if (!p)
300 return p;
301 setTag(p, tag);
302 return p;
303 }
304
305 extern "C" void __wrap_free(void* ptr)
306 {
307 if (!isChunkInUse(ptr))
308 __debugbreak();
309 __real_free(ptr);
310 }
311
312 static int isChunkInUse(void* pv)
313 {
314 unsigned int* pFooter = footerForChunk(pv);
315 return pFooter[1] & 1;
316 }
317
318 __attribute__((naked)) void* operator new(size_t size)
319 {
320 __asm (
321 ".syntax unified\n"
322 ".thumb\n"
323 "push {r4,lr}\n"
324 "mov r1,lr\n"
325 "bl mallocWithTag\n"
326 "cbnz r0, 1$\n"
327 "bl abort\n"
328 "1$:\n"
329 "pop {r4,pc}\n"
330 );
331 // This line never executes but silences no return value warning from compiler.
332 return (void*)1;
333 }
334
335 #else
336
337 /* Wrap memory allocation routines to make sure that they aren't being called from interrupt handler. */
338 static void breakOnHeapOpFromInterruptHandler(void)
339 {
340 if (__get_IPSR() != 0)
341 __debugbreak();
342 }
343
344 extern "C" void* __real_malloc(size_t size);
345 extern "C" void* __wrap_malloc(size_t size)
346 {
347 breakOnHeapOpFromInterruptHandler();
348 return __real_malloc(size);
349 }
350
351
352 extern "C" void* __real_realloc(void* ptr, size_t size);
353 extern "C" void* __wrap_realloc(void* ptr, size_t size)
354 {
355 breakOnHeapOpFromInterruptHandler();
356 return __real_realloc(ptr, size);
357 }
358
359
360 extern "C" void __real_free(void* ptr);
361 extern "C" void __wrap_free(void* ptr)
362 {
363 breakOnHeapOpFromInterruptHandler();
364 __real_free(ptr);
365 }
366
367 #endif // HEAP_TAGS