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