Keep memory options together in makefile.
[clinton/Smoothieware.git] / gcc4mbed / src / gcc4mbed.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;
cdefb14d
AG
37extern "C" unsigned int __HeapBase;
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
184extern "C" int __aeabi_unwind_cpp_pr0(int state, void* controlBlock, void* context)
185{
186 abort();
187}
188
189
190extern "C" int __aeabi_unwind_cpp_pr1(int state, void* controlBlock, void* context)
191{
192 abort();
193}
194
195
196extern "C" int __aeabi_unwind_cpp_pr2(int state, void* controlBlock, void* context)
197{
198 abort();
199}
200
201/* Trap calls to malloc/free/realloc in ISR. */
202extern "C" void __malloc_lock(void)
203{
204 if (__get_IPSR() != 0)
205 __debugbreak();
206}
207
208extern "C" void __malloc_unlock(void)
209{
210}
211
212
60c34c05
AG
213/* Turn off the errno macro and use actual external global variable instead. */
214#undef errno
215extern int errno;
216
ddf5038e
AG
217static int doesHeapCollideWithStack(unsigned int newHeap);
218
60c34c05
AG
219/* Dynamic memory allocation related syscalls. */
220extern "C" caddr_t _sbrk(int incr)
221{
222 static unsigned char* heap = (unsigned char*)&__HeapBase;
223 unsigned char* prev_heap = heap;
224 unsigned char* new_heap = heap + incr;
225
ddf5038e
AG
226 if (doesHeapCollideWithStack((unsigned int)new_heap))
227 {
60c34c05
AG
228 errno = ENOMEM;
229 return (caddr_t)-1;
230 }
231
232 heap = new_heap;
233 return (caddr_t) prev_heap;
234}
235
ddf5038e
AG
236static int doesHeapCollideWithStack(unsigned int newHeap)
237{
238 return ((newHeap >= __get_MSP()) ||
239 (STACK_SIZE && newHeap >= g_maximumHeapAddress));
240}
241
60c34c05
AG
242
243/* Optional functionality which will tag each heap allocation with the caller's return address. */
b3e1627c 244#ifdef HEAP_TAGS
60c34c05
AG
245
246const unsigned int* __smoothieHeapBase = &__HeapBase;
247
248extern "C" void* __real_malloc(size_t size);
249extern "C" void* __real_realloc(void* ptr, size_t size);
b3e1627c 250extern "C" void __real_free(void* ptr);
60c34c05
AG
251
252static void setTag(void* pv, unsigned int tag);
253static unsigned int* footerForChunk(void* pv);
254static unsigned int* headerForChunk(void* pv);
255static unsigned int sizeOfChunk(unsigned int* pHeader);
b3e1627c 256static int isChunkInUse(void* pv);
60c34c05
AG
257
258extern "C" __attribute__((naked)) void __wrap_malloc(size_t size)
259{
260 __asm (
261 ".syntax unified\n"
262 ".thumb\n"
263 "mov r1,lr\n"
264 "b mallocWithTag\n"
265 );
266}
267
268extern "C" void* mallocWithTag(size_t size, unsigned int tag)
269{
270 void* p = __real_malloc(size + sizeof(tag));
271 if (!p && __smoothieHeapBase)
272 return p;
273 setTag(p, tag);
274 return p;
275}
276
277static void setTag(void* pv, unsigned int tag)
278{
279 unsigned int* pFooter = footerForChunk(pv);
280 *pFooter = tag;
281}
282
283static unsigned int* footerForChunk(void* pv)
284{
285 unsigned int* pHeader = headerForChunk(pv);
286 unsigned int size = sizeOfChunk(pHeader);
287 return (unsigned int*)(void*)((char*)pHeader + size);
288}
289
290static unsigned int* headerForChunk(void* pv)
291{
292 // Header is allocated two words (8 bytes) before the publicly returned allocation chunk address.
293 unsigned int* p = (unsigned int*)pv;
294 return &p[-2];
295}
296
297static unsigned int sizeOfChunk(unsigned int* pHeader)
298{
299 /* Remove previous chunk in use flag. */
300 return pHeader[1] & ~1;
301}
302
303extern "C" __attribute__((naked)) void __wrap_realloc(void* ptr, size_t size)
304{
305 __asm (
306 ".syntax unified\n"
307 ".thumb\n"
308 "mov r2,lr\n"
309 "b reallocWithTag\n"
310 );
311}
312
313extern "C" void* reallocWithTag(void* ptr, size_t size, unsigned int tag)
314{
315 void* p = __real_realloc(ptr, size + sizeof(tag));
316 if (!p)
317 return p;
318 setTag(p, tag);
319 return p;
320}
321
b3e1627c
AG
322extern "C" void __wrap_free(void* ptr)
323{
324 if (!isChunkInUse(ptr))
325 __debugbreak();
326 __real_free(ptr);
327}
328
329static int isChunkInUse(void* pv)
330{
331 unsigned int* pFooter = footerForChunk(pv);
332 return pFooter[1] & 1;
333}
334
60c34c05
AG
335__attribute__((naked)) void* operator new(size_t size)
336{
337 __asm (
338 ".syntax unified\n"
339 ".thumb\n"
340 "push {r4,lr}\n"
341 "mov r1,lr\n"
342 "bl mallocWithTag\n"
343 "cbnz r0, 1$\n"
344 "bl abort\n"
345 "1$:\n"
346 "pop {r4,pc}\n"
347 );
b3e1627c
AG
348 // This line never executes but silences no return value warning from compiler.
349 return (void*)1;
60c34c05
AG
350}
351
352#endif // HEAP_TAGS