disable endstos if there is a configuration error
[clinton/Smoothieware.git] / build / mbed_custom.cpp
... / ...
CommitLineData
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
25unsigned int g_maximumHeapAddress;
26
27static void fillUnusedRAM(void);
28static void configureStackSizeLimit(unsigned int stackSizeLimit);
29static unsigned int alignTo32Bytes(unsigned int value);
30static void configureMpuToCatchStackOverflowIntoHeap(unsigned int maximumHeapAddress);
31static void configureMpuRegionToAccessAllMemoryWithNoCaching(void);
32
33
34/* Symbols exposed from the linker script. */
35extern unsigned int __bss_start__;
36extern unsigned int __bss_end__;
37extern unsigned int __StackTop;
38extern "C" unsigned int __end__;
39
40extern "C" int main(void);
41extern "C" void __libc_init_array(void);
42// extern "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);
49 fillUnusedRAM();
50
51 if (STACK_SIZE) {
52 configureStackSizeLimit(STACK_SIZE);
53 }
54 if (WRITE_BUFFER_DISABLE) {
55 disableMPU();
56 configureMpuRegionToAccessAllMemoryWithNoCaching();
57 enableMPU();
58 }
59 if (MRI_ENABLE) {
60 __mriInit(MRI_INIT_PARAMETERS);
61 if (MRI_BREAK_ON_INIT)
62 __debugbreak();
63 }
64
65
66 // MemoryPool stuff - needs to be initialised before __libc_init_array
67 // so static ctors can use them
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);
81
82
83 _AHB0 = &_AHB0_stack;
84 _AHB1 = &_AHB1_stack;
85 // MemoryPool init done
86
87 __libc_init_array();
88 mainReturnValue = main();
89 exit(mainReturnValue);
90}
91
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
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{
127#define MPU_REGION_SIZE_OF_32_BYTES ((5-1) << MPU_RASR_SIZE_SHIFT) // 2^5 = 32 bytes.
128
129 prepareToAccessMPURegion(getHighestMPUDataRegionIndex());
130 setMPURegionAddress(maximumHeapAddress);
131 setMPURegionAttributeAndSize(MPU_REGION_SIZE_OF_32_BYTES | MPU_RASR_ENABLE);
132 enableMPUWithDefaultMemoryMap();
133}
134
135static void configureMpuRegionToAccessAllMemoryWithNoCaching(void)
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;
142 uint32_t regionIndex = STACK_SIZE ? getHighestMPUDataRegionIndex() - 1 : getHighestMPUDataRegionIndex();
143
144 prepareToAccessMPURegion(regionIndex);
145 setMPURegionAddress(regionToStartAtAddress0);
146 setMPURegionAttributeAndSize(regionSizeAndAttributes);
147}
148
149
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);
155 return __real__read(file, ptr, len);
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();
192
193 exit(1);
194}
195
196
197extern "C" void __cxa_pure_virtual(void)
198{
199 abort();
200}
201
202
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
215/* Turn off the errno macro and use actual external global variable instead. */
216#undef errno
217extern int errno;
218
219static int doesHeapCollideWithStack(unsigned int newHeap);
220
221/* Dynamic memory allocation related syscalls. */
222extern "C" caddr_t _sbrk(int incr)
223{
224 static unsigned char *heap = (unsigned char *)&__end__;
225 unsigned char *prev_heap = heap;
226 unsigned char *new_heap = heap + incr;
227
228 if (doesHeapCollideWithStack((unsigned int)new_heap)) {
229 errno = ENOMEM;
230 return (caddr_t) - 1;
231 }
232
233 heap = new_heap;
234 return (caddr_t) prev_heap;
235}
236
237static int doesHeapCollideWithStack(unsigned int newHeap)
238{
239 return ((newHeap >= __get_MSP()) ||
240 (STACK_SIZE && newHeap >= g_maximumHeapAddress));
241}
242
243
244/* Optional functionality which will tag each heap allocation with the caller's return address. */
245#ifdef HEAP_TAGS
246
247const unsigned int *__smoothieHeapBase = &__end__;
248
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);
252
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);
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
269extern "C" void *mallocWithTag(size_t size, unsigned int tag)
270{
271 void *p = __real_malloc(size + sizeof(tag));
272 if (!p && __smoothieHeapBase)
273 return p;
274 setTag(p, tag);
275 return p;
276}
277
278static void setTag(void *pv, unsigned int tag)
279{
280 unsigned int *pFooter = footerForChunk(pv);
281 *pFooter = tag;
282}
283
284static unsigned int *footerForChunk(void *pv)
285{
286 unsigned int *pHeader = headerForChunk(pv);
287 unsigned int size = sizeOfChunk(pHeader);
288 return (unsigned int *)(void *)((char *)pHeader + size);
289}
290
291static unsigned int *headerForChunk(void *pv)
292{
293 // Header is allocated two words (8 bytes) before the publicly returned allocation chunk address.
294 unsigned int *p = (unsigned int *)pv;
295 return &p[-2];
296}
297
298static unsigned int sizeOfChunk(unsigned int *pHeader)
299{
300 /* Remove previous chunk in use flag. */
301 return pHeader[1] & ~1;
302}
303
304extern "C" __attribute__((naked)) void __wrap_realloc(void *ptr, size_t size)
305{
306 __asm (
307 ".syntax unified\n"
308 ".thumb\n"
309 "mov r2,lr\n"
310 "b reallocWithTag\n"
311 );
312}
313
314extern "C" void *reallocWithTag(void *ptr, size_t size, unsigned int tag)
315{
316 void *p = __real_realloc(ptr, size + sizeof(tag));
317 if (!p)
318 return p;
319 setTag(p, tag);
320 return p;
321}
322
323extern "C" void __wrap_free(void *ptr)
324{
325 if (!isChunkInUse(ptr))
326 __debugbreak();
327 __real_free(ptr);
328}
329
330static int isChunkInUse(void *pv)
331{
332 unsigned int *pFooter = footerForChunk(pv);
333 return pFooter[1] & 1;
334}
335
336__attribute__((naked)) void *operator new(size_t size)
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 );
349 // This line never executes but silences no return value warning from compiler.
350 return (void *)1;
351}
352
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
362extern "C" void *__real_malloc(size_t size);
363extern "C" void *__wrap_malloc(size_t size)
364{
365 breakOnHeapOpFromInterruptHandler();
366 return __real_malloc(size);
367}
368
369
370extern "C" void *__real_realloc(void *ptr, size_t size);
371extern "C" void *__wrap_realloc(void *ptr, size_t size)
372{
373 breakOnHeapOpFromInterruptHandler();
374 return __real_realloc(ptr, size);
375}
376
377
378extern "C" void __real_free(void *ptr);
379extern "C" void __wrap_free(void *ptr)
380{
381 breakOnHeapOpFromInterruptHandler();
382 __real_free(ptr);
383}
384
385#endif // HEAP_TAGS