Merge branch 'edge' into track_allocs
[clinton/Smoothieware.git] / gcc4mbed / src / gcc4mbed.cpp
CommitLineData
60c34c05
AG
1/* Copyright 2012 Adam Green (http://mbed.org/users/AdamGreen/)
2
3 This program is free software: you can redistribute it and/or modify
4 it under the terms of the GNU Lesser General Public License as published
5 by the Free Software Foundation, either version 3 of the License, or
6 (at your option) any later version.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU Lesser General Public License for more details.
12
13 You should have received a copy of the GNU Lesser General Public License
14 along with this program. If not, see <http://www.gnu.org/licenses/>.
15*/
16/* Provide routines which hook the MRI debug monitor into GCC4MBED projects. */
17#include <string.h>
18#include <sys/types.h>
19#include <errno.h>
20#include <mri.h>
21#include <cmsis.h>
65eee97a
AG
22#include "mpu.h"
23
24static void configureHighestMpuRegionToAccessAllMemoryWithNoCaching(void);
60c34c05
AG
25
26extern unsigned int __bss_start__;
27extern unsigned int __bss_end__;
28extern "C" int main(void);
29extern "C" void __libc_init_array(void);
30extern "C" void exit(int ErrorCode);
31extern "C" void _start(void)
32{
33 int bssSize = (int)&__bss_end__ - (int)&__bss_start__;
34 int mainReturnValue;
35
36 memset(&__bss_start__, 0, bssSize);
37
65eee97a
AG
38 if (WRITE_BUFFER_DISABLE)
39 {
40 disableMPU();
41 configureHighestMpuRegionToAccessAllMemoryWithNoCaching();
42 enableMPU();
43 }
60c34c05
AG
44 if (MRI_ENABLE)
45 {
46 __mriInit(MRI_INIT_PARAMETERS);
47 if (MRI_BREAK_ON_INIT)
48 __debugbreak();
49 }
50
51 __libc_init_array();
52 mainReturnValue = main();
53 exit(mainReturnValue);
54}
55
65eee97a
AG
56static void configureHighestMpuRegionToAccessAllMemoryWithNoCaching(void)
57{
58 static const uint32_t regionToStartAtAddress0 = 0U;
59 static const uint32_t regionReadWrite = 1 << MPU_RASR_AP_SHIFT;
60 static const uint32_t regionSizeAt4GB = 31 << MPU_RASR_SIZE_SHIFT; /* 4GB = 2^(31+1) */
61 static const uint32_t regionEnable = MPU_RASR_ENABLE;
62 static const uint32_t regionSizeAndAttributes = regionReadWrite | regionSizeAt4GB | regionEnable;
63
64 prepareToAccessMPURegion(getHighestMPUDataRegionIndex());
65 setMPURegionAddress(regionToStartAtAddress0);
66 setMPURegionAttributeAndSize(regionSizeAndAttributes);
67}
68
69
60c34c05
AG
70
71extern "C" int __real__read(int file, char *ptr, int len);
72extern "C" int __wrap__read(int file, char *ptr, int len)
73{
74 if (MRI_SEMIHOST_STDIO && file < 3)
75 return __mriNewlib_SemihostRead(file, ptr, len);
76 return __real__read(file, ptr, len);
77}
78
79
80extern "C" int __real__write(int file, char *ptr, int len);
81extern "C" int __wrap__write(int file, char *ptr, int len)
82{
83 if (MRI_SEMIHOST_STDIO && file < 3)
84 return __mriNewlib_SemihostWrite(file, ptr, len);
85 return __real__write(file, ptr, len);
86}
87
88
89extern "C" int __real__isatty(int file);
90extern "C" int __wrap__isatty(int file)
91{
92 /* Hardcoding the stdin/stdout/stderr handles to be interactive tty devices, unlike mbed.ar */
93 if (file < 3)
94 return 1;
95 return __real__isatty(file);
96}
97
98
99extern "C" int __wrap_semihost_connected(void)
100{
101 /* MRI makes it look like there is no mbed interface attached since it disables the JTAG portion but MRI does
102 support some of the mbed semihost calls when it is running so force it to return -1, indicating that the
103 interface is attached. */
104 return -1;
105}
106
107
108
109extern "C" void abort(void)
110{
111 if (MRI_ENABLE)
112 __debugbreak();
113
114 exit(1);
115}
116
117
118extern "C" void __cxa_pure_virtual(void)
119{
120 abort();
121}
122
123
124extern "C" int __aeabi_unwind_cpp_pr0(int state, void* controlBlock, void* context)
125{
126 abort();
127}
128
129
130extern "C" int __aeabi_unwind_cpp_pr1(int state, void* controlBlock, void* context)
131{
132 abort();
133}
134
135
136extern "C" int __aeabi_unwind_cpp_pr2(int state, void* controlBlock, void* context)
137{
138 abort();
139}
140
141/* Trap calls to malloc/free/realloc in ISR. */
142extern "C" void __malloc_lock(void)
143{
144 if (__get_IPSR() != 0)
145 __debugbreak();
146}
147
148extern "C" void __malloc_unlock(void)
149{
150}
151
152
153/* Linker defined symbol to be used by sbrk for where dynamically heap should start. */
154extern "C" unsigned int __HeapBase;
155
156/* Turn off the errno macro and use actual external global variable instead. */
157#undef errno
158extern int errno;
159
160/* Dynamic memory allocation related syscalls. */
161extern "C" caddr_t _sbrk(int incr)
162{
163 static unsigned char* heap = (unsigned char*)&__HeapBase;
164 unsigned char* prev_heap = heap;
165 unsigned char* new_heap = heap + incr;
166
167 if (new_heap >= (unsigned char*)__get_MSP()) {
168 errno = ENOMEM;
169 return (caddr_t)-1;
170 }
171
172 heap = new_heap;
173 return (caddr_t) prev_heap;
174}
175
176
177/* Optional functionality which will tag each heap allocation with the caller's return address. */
178#if HEAP_TAGS
179
180const unsigned int* __smoothieHeapBase = &__HeapBase;
181
182extern "C" void* __real_malloc(size_t size);
183extern "C" void* __real_realloc(void* ptr, size_t size);
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);
189
190extern "C" __attribute__((naked)) void __wrap_malloc(size_t size)
191{
192 __asm (
193 ".syntax unified\n"
194 ".thumb\n"
195 "mov r1,lr\n"
196 "b mallocWithTag\n"
197 );
198}
199
200extern "C" void* mallocWithTag(size_t size, unsigned int tag)
201{
202 void* p = __real_malloc(size + sizeof(tag));
203 if (!p && __smoothieHeapBase)
204 return p;
205 setTag(p, tag);
206 return p;
207}
208
209static void setTag(void* pv, unsigned int tag)
210{
211 unsigned int* pFooter = footerForChunk(pv);
212 *pFooter = tag;
213}
214
215static unsigned int* footerForChunk(void* pv)
216{
217 unsigned int* pHeader = headerForChunk(pv);
218 unsigned int size = sizeOfChunk(pHeader);
219 return (unsigned int*)(void*)((char*)pHeader + size);
220}
221
222static unsigned int* headerForChunk(void* pv)
223{
224 // Header is allocated two words (8 bytes) before the publicly returned allocation chunk address.
225 unsigned int* p = (unsigned int*)pv;
226 return &p[-2];
227}
228
229static unsigned int sizeOfChunk(unsigned int* pHeader)
230{
231 /* Remove previous chunk in use flag. */
232 return pHeader[1] & ~1;
233}
234
235extern "C" __attribute__((naked)) void __wrap_realloc(void* ptr, size_t size)
236{
237 __asm (
238 ".syntax unified\n"
239 ".thumb\n"
240 "mov r2,lr\n"
241 "b reallocWithTag\n"
242 );
243}
244
245extern "C" void* reallocWithTag(void* ptr, size_t size, unsigned int tag)
246{
247 void* p = __real_realloc(ptr, size + sizeof(tag));
248 if (!p)
249 return p;
250 setTag(p, tag);
251 return p;
252}
253
254__attribute__((naked)) void* operator new(size_t size)
255{
256 __asm (
257 ".syntax unified\n"
258 ".thumb\n"
259 "push {r4,lr}\n"
260 "mov r1,lr\n"
261 "bl mallocWithTag\n"
262 "cbnz r0, 1$\n"
263 "bl abort\n"
264 "1$:\n"
265 "pop {r4,pc}\n"
266 );
267}
268
269#endif // HEAP_TAGS