Merge remote-tracking branch 'upstream/edge' into firmconfig
[clinton/Smoothieware.git] / build / mbed_custom.cpp
CommitLineData
ae159ef4 1/* Copyright 2013 Adam Green (http://mbed.org/users/AdamGreen/)
60c34c05 2
ae159ef4
AG
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
60c34c05 6
ae159ef4 7 http://www.apache.org/licenses/LICENSE-2.0
60c34c05 8
ae159ef4
AG
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.
60c34c05
AG
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>
65eee97a
AG
21#include "mpu.h"
22
cdefb14d 23
ddf5038e
AG
24static unsigned int g_maximumHeapAddress;
25
cdefb14d 26static void fillUnusedRAM(void);
ddf5038e
AG
27static void configureStackSizeLimit(unsigned int stackSizeLimit);
28static unsigned int alignTo32Bytes(unsigned int value);
29static void configureMpuToCatchStackOverflowIntoHeap(unsigned int maximumHeapAddress);
30static void configureMpuRegionToAccessAllMemoryWithNoCaching(void);
60c34c05 31
cdefb14d 32
ddf5038e 33/* Symbols exposed from the linker script. */
cdefb14d
AG
34extern unsigned int __bss_start__;
35extern unsigned int __bss_end__;
ddf5038e 36extern unsigned int __StackTop;
ec7b59de 37extern "C" unsigned int __end__;
cdefb14d
AG
38
39
60c34c05
AG
40extern "C" int main(void);
41extern "C" void __libc_init_array(void);
42extern "C" void exit(int ErrorCode);
43extern "C" void _start(void)
44{
45 int bssSize = (int)&__bss_end__ - (int)&__bss_start__;
46 int mainReturnValue;
47
48 memset(&__bss_start__, 0, bssSize);
cdefb14d 49 fillUnusedRAM();
ddf5038e
AG
50
51 if (STACK_SIZE)
52 {
53 configureStackSizeLimit(STACK_SIZE);
54 }
65eee97a
AG
55 if (WRITE_BUFFER_DISABLE)
56 {
57 disableMPU();
ddf5038e 58 configureMpuRegionToAccessAllMemoryWithNoCaching();
65eee97a
AG
59 enableMPU();
60 }
60c34c05
AG
61 if (MRI_ENABLE)
62 {
63 __mriInit(MRI_INIT_PARAMETERS);
64 if (MRI_BREAK_ON_INIT)
65 __debugbreak();
66 }
cdefb14d 67
60c34c05
AG
68 __libc_init_array();
69 mainReturnValue = main();
70 exit(mainReturnValue);
71}
72
cdefb14d
AG
73static __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
ddf5038e
AG
94static 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
101static unsigned int alignTo32Bytes(unsigned int value)
102{
103 return (value + 31) & ~31;
104}
105
106static 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}
cdefb14d 115
ddf5038e 116static void configureMpuRegionToAccessAllMemoryWithNoCaching(void)
65eee97a
AG
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;
ddf5038e 123 uint32_t regionIndex = STACK_SIZE ? getHighestMPUDataRegionIndex() - 1 : getHighestMPUDataRegionIndex();
65eee97a 124
ddf5038e 125 prepareToAccessMPURegion(regionIndex);
65eee97a
AG
126 setMPURegionAddress(regionToStartAtAddress0);
127 setMPURegionAttributeAndSize(regionSizeAndAttributes);
128}
129
130
60c34c05
AG
131extern "C" int __real__read(int file, char *ptr, int len);
132extern "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
140extern "C" int __real__write(int file, char *ptr, int len);
141extern "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
149extern "C" int __real__isatty(int file);
150extern "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
159extern "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
169extern "C" void abort(void)
170{
171 if (MRI_ENABLE)
172 __debugbreak();
173
174 exit(1);
175}
176
177
178extern "C" void __cxa_pure_virtual(void)
179{
180 abort();
181}
182
183
60c34c05
AG
184/* Trap calls to malloc/free/realloc in ISR. */
185extern "C" void __malloc_lock(void)
186{
187 if (__get_IPSR() != 0)
188 __debugbreak();
189}
190
191extern "C" void __malloc_unlock(void)
192{
193}
194
195
60c34c05
AG
196/* Turn off the errno macro and use actual external global variable instead. */
197#undef errno
198extern int errno;
199
ddf5038e
AG
200static int doesHeapCollideWithStack(unsigned int newHeap);
201
60c34c05
AG
202/* Dynamic memory allocation related syscalls. */
203extern "C" caddr_t _sbrk(int incr)
204{
ec7b59de 205 static unsigned char* heap = (unsigned char*)&__end__;
60c34c05
AG
206 unsigned char* prev_heap = heap;
207 unsigned char* new_heap = heap + incr;
208
ddf5038e
AG
209 if (doesHeapCollideWithStack((unsigned int)new_heap))
210 {
60c34c05
AG
211 errno = ENOMEM;
212 return (caddr_t)-1;
213 }
214
215 heap = new_heap;
216 return (caddr_t) prev_heap;
217}
218
ddf5038e
AG
219static int doesHeapCollideWithStack(unsigned int newHeap)
220{
221 return ((newHeap >= __get_MSP()) ||
222 (STACK_SIZE && newHeap >= g_maximumHeapAddress));
223}
224
60c34c05
AG
225
226/* Optional functionality which will tag each heap allocation with the caller's return address. */
b3e1627c 227#ifdef HEAP_TAGS
60c34c05 228
ec7b59de 229const unsigned int* __smoothieHeapBase = &__end__;
60c34c05
AG
230
231extern "C" void* __real_malloc(size_t size);
232extern "C" void* __real_realloc(void* ptr, size_t size);
b3e1627c 233extern "C" void __real_free(void* ptr);
60c34c05
AG
234
235static void setTag(void* pv, unsigned int tag);
236static unsigned int* footerForChunk(void* pv);
237static unsigned int* headerForChunk(void* pv);
238static unsigned int sizeOfChunk(unsigned int* pHeader);
b3e1627c 239static int isChunkInUse(void* pv);
60c34c05
AG
240
241extern "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
251extern "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
260static void setTag(void* pv, unsigned int tag)
261{
262 unsigned int* pFooter = footerForChunk(pv);
263 *pFooter = tag;
264}
265
266static 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
273static 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
280static unsigned int sizeOfChunk(unsigned int* pHeader)
281{
282 /* Remove previous chunk in use flag. */
283 return pHeader[1] & ~1;
284}
285
286extern "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
296extern "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
b3e1627c
AG
305extern "C" void __wrap_free(void* ptr)
306{
307 if (!isChunkInUse(ptr))
308 __debugbreak();
309 __real_free(ptr);
310}
311
312static int isChunkInUse(void* pv)
313{
314 unsigned int* pFooter = footerForChunk(pv);
315 return pFooter[1] & 1;
316}
317
60c34c05
AG
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 );
b3e1627c
AG
331 // This line never executes but silences no return value warning from compiler.
332 return (void*)1;
60c34c05
AG
333}
334
b4e5c830
AG
335#else
336
337/* Wrap memory allocation routines to make sure that they aren't being called from interrupt handler. */
338static void breakOnHeapOpFromInterruptHandler(void)
339{
340 if (__get_IPSR() != 0)
341 __debugbreak();
342}
343
344extern "C" void* __real_malloc(size_t size);
345extern "C" void* __wrap_malloc(size_t size)
346{
347 breakOnHeapOpFromInterruptHandler();
348 return __real_malloc(size);
349}
350
351
352extern "C" void* __real_realloc(void* ptr, size_t size);
353extern "C" void* __wrap_realloc(void* ptr, size_t size)
354{
355 breakOnHeapOpFromInterruptHandler();
356 return __real_realloc(ptr, size);
357}
358
359
360extern "C" void __real_free(void* ptr);
361extern "C" void __wrap_free(void* ptr)
362{
363 breakOnHeapOpFromInterruptHandler();
364 __real_free(ptr);
365}
366
60c34c05 367#endif // HEAP_TAGS