Merge pull request #1342 from wolfmanjm/query-for-http
[clinton/Smoothieware.git] / build / mbed_custom.cpp
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
25 unsigned int g_maximumHeapAddress;
26
27 static void fillUnusedRAM(void);
28 static void configureStackSizeLimit(unsigned int stackSizeLimit);
29 static unsigned int alignTo32Bytes(unsigned int value);
30 static void configureMpuToCatchStackOverflowIntoHeap(unsigned int maximumHeapAddress);
31 static void configureMpuRegionToAccessAllMemoryWithNoCaching(void);
32
33
34 /* Symbols exposed from the linker script. */
35 extern unsigned int __bss_start__;
36 extern unsigned int __bss_end__;
37 extern unsigned int __StackTop;
38 extern "C" unsigned int __end__;
39
40 extern "C" int main(void);
41 extern "C" void __libc_init_array(void);
42 // extern "C" void exit(int ErrorCode);
43 extern "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
92 static __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
113 static 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
120 static unsigned int alignTo32Bytes(unsigned int value)
121 {
122 return (value + 31) & ~31;
123 }
124
125 static 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
135 static 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
150 extern "C" int __real__read(int file, char *ptr, int len);
151 extern "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
159 extern "C" int __real__write(int file, char *ptr, int len);
160 extern "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
168 extern "C" int __real__isatty(int file);
169 extern "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
178 extern "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
188 extern "C" void abort(void)
189 {
190 if (MRI_ENABLE)
191 __debugbreak();
192
193 exit(1);
194 }
195
196
197 extern "C" void __cxa_pure_virtual(void)
198 {
199 abort();
200 }
201
202
203 /* Trap calls to malloc/free/realloc in ISR. */
204 extern "C" void __malloc_lock(void)
205 {
206 if (__get_IPSR() != 0)
207 __debugbreak();
208 }
209
210 extern "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
217 extern int errno;
218
219 static int doesHeapCollideWithStack(unsigned int newHeap);
220
221 /* Dynamic memory allocation related syscalls. */
222 extern "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
237 static 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
247 const unsigned int *__smoothieHeapBase = &__end__;
248
249 extern "C" void *__real_malloc(size_t size);
250 extern "C" void *__real_realloc(void *ptr, size_t size);
251 extern "C" void __real_free(void *ptr);
252
253 static void setTag(void *pv, unsigned int tag);
254 static unsigned int *footerForChunk(void *pv);
255 static unsigned int *headerForChunk(void *pv);
256 static unsigned int sizeOfChunk(unsigned int *pHeader);
257 static int isChunkInUse(void *pv);
258
259 extern "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
269 extern "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
278 static void setTag(void *pv, unsigned int tag)
279 {
280 unsigned int *pFooter = footerForChunk(pv);
281 *pFooter = tag;
282 }
283
284 static 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
291 static 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
298 static unsigned int sizeOfChunk(unsigned int *pHeader)
299 {
300 /* Remove previous chunk in use flag. */
301 return pHeader[1] & ~1;
302 }
303
304 extern "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
314 extern "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
323 extern "C" void __wrap_free(void *ptr)
324 {
325 if (!isChunkInUse(ptr))
326 __debugbreak();
327 __real_free(ptr);
328 }
329
330 static 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. */
356 static void breakOnHeapOpFromInterruptHandler(void)
357 {
358 if (__get_IPSR() != 0)
359 __debugbreak();
360 }
361
362 extern "C" void *__real_malloc(size_t size);
363 extern "C" void *__wrap_malloc(size_t size)
364 {
365 breakOnHeapOpFromInterruptHandler();
366 return __real_malloc(size);
367 }
368
369
370 extern "C" void *__real_realloc(void *ptr, size_t size);
371 extern "C" void *__wrap_realloc(void *ptr, size_t size)
372 {
373 breakOnHeapOpFromInterruptHandler();
374 return __real_realloc(ptr, size);
375 }
376
377
378 extern "C" void __real_free(void *ptr);
379 extern "C" void __wrap_free(void *ptr)
380 {
381 breakOnHeapOpFromInterruptHandler();
382 __real_free(ptr);
383 }
384
385 #endif // HEAP_TAGS