Merge branch 'edge' into track_allocs
[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
23static void configureHighestMpuRegionToAccessAllMemoryWithNoCaching(void);
60c34c05
AG
24
25extern unsigned int __bss_start__;
26extern unsigned int __bss_end__;
27extern "C" int main(void);
28extern "C" void __libc_init_array(void);
29extern "C" void exit(int ErrorCode);
30extern "C" void _start(void)
31{
32 int bssSize = (int)&__bss_end__ - (int)&__bss_start__;
33 int mainReturnValue;
34
35 memset(&__bss_start__, 0, bssSize);
36
65eee97a
AG
37 if (WRITE_BUFFER_DISABLE)
38 {
39 disableMPU();
40 configureHighestMpuRegionToAccessAllMemoryWithNoCaching();
41 enableMPU();
42 }
60c34c05
AG
43 if (MRI_ENABLE)
44 {
45 __mriInit(MRI_INIT_PARAMETERS);
46 if (MRI_BREAK_ON_INIT)
47 __debugbreak();
48 }
49
50 __libc_init_array();
51 mainReturnValue = main();
52 exit(mainReturnValue);
53}
54
65eee97a
AG
55static void configureHighestMpuRegionToAccessAllMemoryWithNoCaching(void)
56{
57 static const uint32_t regionToStartAtAddress0 = 0U;
58 static const uint32_t regionReadWrite = 1 << MPU_RASR_AP_SHIFT;
59 static const uint32_t regionSizeAt4GB = 31 << MPU_RASR_SIZE_SHIFT; /* 4GB = 2^(31+1) */
60 static const uint32_t regionEnable = MPU_RASR_ENABLE;
61 static const uint32_t regionSizeAndAttributes = regionReadWrite | regionSizeAt4GB | regionEnable;
62
63 prepareToAccessMPURegion(getHighestMPUDataRegionIndex());
64 setMPURegionAddress(regionToStartAtAddress0);
65 setMPURegionAttributeAndSize(regionSizeAndAttributes);
66}
67
68
60c34c05
AG
69
70extern "C" int __real__read(int file, char *ptr, int len);
71extern "C" int __wrap__read(int file, char *ptr, int len)
72{
73 if (MRI_SEMIHOST_STDIO && file < 3)
74 return __mriNewlib_SemihostRead(file, ptr, len);
75 return __real__read(file, ptr, len);
76}
77
78
79extern "C" int __real__write(int file, char *ptr, int len);
80extern "C" int __wrap__write(int file, char *ptr, int len)
81{
82 if (MRI_SEMIHOST_STDIO && file < 3)
83 return __mriNewlib_SemihostWrite(file, ptr, len);
84 return __real__write(file, ptr, len);
85}
86
87
88extern "C" int __real__isatty(int file);
89extern "C" int __wrap__isatty(int file)
90{
91 /* Hardcoding the stdin/stdout/stderr handles to be interactive tty devices, unlike mbed.ar */
92 if (file < 3)
93 return 1;
94 return __real__isatty(file);
95}
96
97
98extern "C" int __wrap_semihost_connected(void)
99{
100 /* MRI makes it look like there is no mbed interface attached since it disables the JTAG portion but MRI does
101 support some of the mbed semihost calls when it is running so force it to return -1, indicating that the
102 interface is attached. */
103 return -1;
104}
105
106
107
108extern "C" void abort(void)
109{
110 if (MRI_ENABLE)
111 __debugbreak();
112
113 exit(1);
114}
115
116
117extern "C" void __cxa_pure_virtual(void)
118{
119 abort();
120}
121
122
123extern "C" int __aeabi_unwind_cpp_pr0(int state, void* controlBlock, void* context)
124{
125 abort();
126}
127
128
129extern "C" int __aeabi_unwind_cpp_pr1(int state, void* controlBlock, void* context)
130{
131 abort();
132}
133
134
135extern "C" int __aeabi_unwind_cpp_pr2(int state, void* controlBlock, void* context)
136{
137 abort();
138}
139
140/* Trap calls to malloc/free/realloc in ISR. */
141extern "C" void __malloc_lock(void)
142{
143 if (__get_IPSR() != 0)
144 __debugbreak();
145}
146
147extern "C" void __malloc_unlock(void)
148{
149}
150
151
152/* Linker defined symbol to be used by sbrk for where dynamically heap should start. */
153extern "C" unsigned int __HeapBase;
154
155/* Turn off the errno macro and use actual external global variable instead. */
156#undef errno
157extern int errno;
158
159/* Dynamic memory allocation related syscalls. */
160extern "C" caddr_t _sbrk(int incr)
161{
162 static unsigned char* heap = (unsigned char*)&__HeapBase;
163 unsigned char* prev_heap = heap;
164 unsigned char* new_heap = heap + incr;
165
166 if (new_heap >= (unsigned char*)__get_MSP()) {
167 errno = ENOMEM;
168 return (caddr_t)-1;
169 }
170
171 heap = new_heap;
172 return (caddr_t) prev_heap;
173}
174
175
176/* Optional functionality which will tag each heap allocation with the caller's return address. */
b3e1627c 177#ifdef HEAP_TAGS
60c34c05
AG
178
179const unsigned int* __smoothieHeapBase = &__HeapBase;
180
181extern "C" void* __real_malloc(size_t size);
182extern "C" void* __real_realloc(void* ptr, size_t size);
b3e1627c 183extern "C" void __real_free(void* ptr);
60c34c05
AG
184
185static void setTag(void* pv, unsigned int tag);
186static unsigned int* footerForChunk(void* pv);
187static unsigned int* headerForChunk(void* pv);
188static unsigned int sizeOfChunk(unsigned int* pHeader);
b3e1627c 189static int isChunkInUse(void* pv);
60c34c05
AG
190
191extern "C" __attribute__((naked)) void __wrap_malloc(size_t size)
192{
193 __asm (
194 ".syntax unified\n"
195 ".thumb\n"
196 "mov r1,lr\n"
197 "b mallocWithTag\n"
198 );
199}
200
201extern "C" void* mallocWithTag(size_t size, unsigned int tag)
202{
203 void* p = __real_malloc(size + sizeof(tag));
204 if (!p && __smoothieHeapBase)
205 return p;
206 setTag(p, tag);
207 return p;
208}
209
210static void setTag(void* pv, unsigned int tag)
211{
212 unsigned int* pFooter = footerForChunk(pv);
213 *pFooter = tag;
214}
215
216static unsigned int* footerForChunk(void* pv)
217{
218 unsigned int* pHeader = headerForChunk(pv);
219 unsigned int size = sizeOfChunk(pHeader);
220 return (unsigned int*)(void*)((char*)pHeader + size);
221}
222
223static unsigned int* headerForChunk(void* pv)
224{
225 // Header is allocated two words (8 bytes) before the publicly returned allocation chunk address.
226 unsigned int* p = (unsigned int*)pv;
227 return &p[-2];
228}
229
230static unsigned int sizeOfChunk(unsigned int* pHeader)
231{
232 /* Remove previous chunk in use flag. */
233 return pHeader[1] & ~1;
234}
235
236extern "C" __attribute__((naked)) void __wrap_realloc(void* ptr, size_t size)
237{
238 __asm (
239 ".syntax unified\n"
240 ".thumb\n"
241 "mov r2,lr\n"
242 "b reallocWithTag\n"
243 );
244}
245
246extern "C" void* reallocWithTag(void* ptr, size_t size, unsigned int tag)
247{
248 void* p = __real_realloc(ptr, size + sizeof(tag));
249 if (!p)
250 return p;
251 setTag(p, tag);
252 return p;
253}
254
b3e1627c
AG
255extern "C" void __wrap_free(void* ptr)
256{
257 if (!isChunkInUse(ptr))
258 __debugbreak();
259 __real_free(ptr);
260}
261
262static int isChunkInUse(void* pv)
263{
264 unsigned int* pFooter = footerForChunk(pv);
265 return pFooter[1] & 1;
266}
267
60c34c05
AG
268__attribute__((naked)) void* operator new(size_t size)
269{
270 __asm (
271 ".syntax unified\n"
272 ".thumb\n"
273 "push {r4,lr}\n"
274 "mov r1,lr\n"
275 "bl mallocWithTag\n"
276 "cbnz r0, 1$\n"
277 "bl abort\n"
278 "1$:\n"
279 "pop {r4,pc}\n"
280 );
b3e1627c
AG
281 // This line never executes but silences no return value warning from compiler.
282 return (void*)1;
60c34c05
AG
283}
284
285#endif // HEAP_TAGS