1 /* Copyright 2013 Adam Green (http://mbed.org/users/AdamGreen/)
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
7 http://www.apache.org/licenses/LICENSE-2.0
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.
15 /* Provide routines which hook the MRI debug monitor into GCC4MBED projects. */
17 #include <sys/types.h>
24 unsigned int g_maximumHeapAddress
;
26 static void fillUnusedRAM(void);
27 static void configureStackSizeLimit(unsigned int stackSizeLimit
);
28 static unsigned int alignTo32Bytes(unsigned int value
);
29 static void configureMpuToCatchStackOverflowIntoHeap(unsigned int maximumHeapAddress
);
30 static void configureMpuRegionToAccessAllMemoryWithNoCaching(void);
33 /* Symbols exposed from the linker script. */
34 extern unsigned int __bss_start__
;
35 extern unsigned int __bss_end__
;
36 extern unsigned int __StackTop
;
37 extern "C" unsigned int __end__
;
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)
45 int bssSize
= (int)&__bss_end__
- (int)&__bss_start__
;
48 memset(&__bss_start__
, 0, bssSize
);
53 configureStackSizeLimit(STACK_SIZE
);
55 if (WRITE_BUFFER_DISABLE
)
58 configureMpuRegionToAccessAllMemoryWithNoCaching();
63 __mriInit(MRI_INIT_PARAMETERS
);
64 if (MRI_BREAK_ON_INIT
)
69 mainReturnValue
= main();
70 exit(mainReturnValue
);
73 static __attribute__((naked
)) void fillUnusedRAM(void)
78 // Fill 2 words (8 bytes) at a time with 0xdeadbeef.
79 " ldr r2, =__FillStart\n"
83 // Don't fill past current stack pointer value.
87 " strd r0, r1, [r2], #8\n"
94 static void configureStackSizeLimit(unsigned int stackSizeLimit
)
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
);
101 static unsigned int alignTo32Bytes(unsigned int value
)
103 return (value
+ 31) & ~31;
106 static void configureMpuToCatchStackOverflowIntoHeap(unsigned int maximumHeapAddress
)
108 #define MPU_REGION_SIZE_OF_32_BYTES ((5-1) << MPU_RASR_SIZE_SHIFT) // 2^5 = 32 bytes.
110 prepareToAccessMPURegion(getHighestMPUDataRegionIndex());
111 setMPURegionAddress(maximumHeapAddress
);
112 setMPURegionAttributeAndSize(MPU_REGION_SIZE_OF_32_BYTES
| MPU_RASR_ENABLE
);
113 enableMPUWithDefaultMemoryMap();
116 static void configureMpuRegionToAccessAllMemoryWithNoCaching(void)
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
;
123 uint32_t regionIndex
= STACK_SIZE
? getHighestMPUDataRegionIndex() - 1 : getHighestMPUDataRegionIndex();
125 prepareToAccessMPURegion(regionIndex
);
126 setMPURegionAddress(regionToStartAtAddress0
);
127 setMPURegionAttributeAndSize(regionSizeAndAttributes
);
131 extern "C" int __real__read(int file
, char *ptr
, int len
);
132 extern "C" int __wrap__read(int file
, char *ptr
, int len
)
134 if (MRI_SEMIHOST_STDIO
&& file
< 3)
135 return __mriNewlib_SemihostRead(file
, ptr
, len
);
136 return __real__read(file
, ptr
, len
);
140 extern "C" int __real__write(int file
, char *ptr
, int len
);
141 extern "C" int __wrap__write(int file
, char *ptr
, int len
)
143 if (MRI_SEMIHOST_STDIO
&& file
< 3)
144 return __mriNewlib_SemihostWrite(file
, ptr
, len
);
145 return __real__write(file
, ptr
, len
);
149 extern "C" int __real__isatty(int file
);
150 extern "C" int __wrap__isatty(int file
)
152 /* Hardcoding the stdin/stdout/stderr handles to be interactive tty devices, unlike mbed.ar */
155 return __real__isatty(file
);
159 extern "C" int __wrap_semihost_connected(void)
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. */
169 extern "C" void abort(void)
178 extern "C" void __cxa_pure_virtual(void)
184 /* Trap calls to malloc/free/realloc in ISR. */
185 extern "C" void __malloc_lock(void)
187 if (__get_IPSR() != 0)
191 extern "C" void __malloc_unlock(void)
196 /* Turn off the errno macro and use actual external global variable instead. */
200 static int doesHeapCollideWithStack(unsigned int newHeap
);
202 /* Dynamic memory allocation related syscalls. */
203 extern "C" caddr_t
_sbrk(int incr
)
205 static unsigned char* heap
= (unsigned char*)&__end__
;
206 unsigned char* prev_heap
= heap
;
207 unsigned char* new_heap
= heap
+ incr
;
209 if (doesHeapCollideWithStack((unsigned int)new_heap
))
216 return (caddr_t
) prev_heap
;
219 static int doesHeapCollideWithStack(unsigned int newHeap
)
221 return ((newHeap
>= __get_MSP()) ||
222 (STACK_SIZE
&& newHeap
>= g_maximumHeapAddress
));
226 /* Optional functionality which will tag each heap allocation with the caller's return address. */
229 const unsigned int* __smoothieHeapBase
= &__end__
;
231 extern "C" void* __real_malloc(size_t size
);
232 extern "C" void* __real_realloc(void* ptr
, size_t size
);
233 extern "C" void __real_free(void* ptr
);
235 static void setTag(void* pv
, unsigned int tag
);
236 static unsigned int* footerForChunk(void* pv
);
237 static unsigned int* headerForChunk(void* pv
);
238 static unsigned int sizeOfChunk(unsigned int* pHeader
);
239 static int isChunkInUse(void* pv
);
241 extern "C" __attribute__((naked
)) void __wrap_malloc(size_t size
)
251 extern "C" void* mallocWithTag(size_t size
, unsigned int tag
)
253 void* p
= __real_malloc(size
+ sizeof(tag
));
254 if (!p
&& __smoothieHeapBase
)
260 static void setTag(void* pv
, unsigned int tag
)
262 unsigned int* pFooter
= footerForChunk(pv
);
266 static unsigned int* footerForChunk(void* pv
)
268 unsigned int* pHeader
= headerForChunk(pv
);
269 unsigned int size
= sizeOfChunk(pHeader
);
270 return (unsigned int*)(void*)((char*)pHeader
+ size
);
273 static unsigned int* headerForChunk(void* pv
)
275 // Header is allocated two words (8 bytes) before the publicly returned allocation chunk address.
276 unsigned int* p
= (unsigned int*)pv
;
280 static unsigned int sizeOfChunk(unsigned int* pHeader
)
282 /* Remove previous chunk in use flag. */
283 return pHeader
[1] & ~1;
286 extern "C" __attribute__((naked
)) void __wrap_realloc(void* ptr
, size_t size
)
296 extern "C" void* reallocWithTag(void* ptr
, size_t size
, unsigned int tag
)
298 void* p
= __real_realloc(ptr
, size
+ sizeof(tag
));
305 extern "C" void __wrap_free(void* ptr
)
307 if (!isChunkInUse(ptr
))
312 static int isChunkInUse(void* pv
)
314 unsigned int* pFooter
= footerForChunk(pv
);
315 return pFooter
[1] & 1;
318 __attribute__((naked
)) void* operator new(size_t size
)
331 // This line never executes but silences no return value warning from compiler.
337 /* Wrap memory allocation routines to make sure that they aren't being called from interrupt handler. */
338 static void breakOnHeapOpFromInterruptHandler(void)
340 if (__get_IPSR() != 0)
344 extern "C" void* __real_malloc(size_t size
);
345 extern "C" void* __wrap_malloc(size_t size
)
347 breakOnHeapOpFromInterruptHandler();
348 return __real_malloc(size
);
352 extern "C" void* __real_realloc(void* ptr
, size_t size
);
353 extern "C" void* __wrap_realloc(void* ptr
, size_t size
)
355 breakOnHeapOpFromInterruptHandler();
356 return __real_realloc(ptr
, size
);
360 extern "C" void __real_free(void* ptr
);
361 extern "C" void __wrap_free(void* ptr
)
363 breakOnHeapOpFromInterruptHandler();