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>
23 #include "platform_memory.h"
25 unsigned int g_maximumHeapAddress
;
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);
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__
;
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
)
68 // MemoryPool stuff - needs to be initialised before __libc_init_array
69 // so static ctors can use them
70 extern uint8_t __AHB0_dyn_start
;
71 extern uint8_t __AHB0_end
;
72 extern uint8_t __AHB1_dyn_start
;
73 extern uint8_t __AHB1_end
;
75 MemoryPool
_AHB0_stack(&__AHB0_dyn_start
, &__AHB0_end
- &__AHB0_dyn_start
);
76 MemoryPool
_AHB1_stack(&__AHB1_dyn_start
, &__AHB1_end
- &__AHB1_dyn_start
);
80 // MemoryPool init done
83 mainReturnValue
= main();
84 exit(mainReturnValue
);
87 static __attribute__((naked
)) void fillUnusedRAM(void)
92 // Fill 2 words (8 bytes) at a time with 0xdeadbeef.
93 " ldr r2, =__FillStart\n"
97 // Don't fill past current stack pointer value.
101 " strd r0, r1, [r2], #8\n"
108 static void configureStackSizeLimit(unsigned int stackSizeLimit
)
110 // Note: 32 bytes are reserved to fall between top of heap and top of stack for minimum MPU guard region.
111 g_maximumHeapAddress
= alignTo32Bytes((unsigned int)&__StackTop
- stackSizeLimit
- 32);
112 configureMpuToCatchStackOverflowIntoHeap(g_maximumHeapAddress
);
115 static unsigned int alignTo32Bytes(unsigned int value
)
117 return (value
+ 31) & ~31;
120 static void configureMpuToCatchStackOverflowIntoHeap(unsigned int maximumHeapAddress
)
122 #define MPU_REGION_SIZE_OF_32_BYTES ((5-1) << MPU_RASR_SIZE_SHIFT) // 2^5 = 32 bytes.
124 prepareToAccessMPURegion(getHighestMPUDataRegionIndex());
125 setMPURegionAddress(maximumHeapAddress
);
126 setMPURegionAttributeAndSize(MPU_REGION_SIZE_OF_32_BYTES
| MPU_RASR_ENABLE
);
127 enableMPUWithDefaultMemoryMap();
130 static void configureMpuRegionToAccessAllMemoryWithNoCaching(void)
132 static const uint32_t regionToStartAtAddress0
= 0U;
133 static const uint32_t regionReadWrite
= 1 << MPU_RASR_AP_SHIFT
;
134 static const uint32_t regionSizeAt4GB
= 31 << MPU_RASR_SIZE_SHIFT
; /* 4GB = 2^(31+1) */
135 static const uint32_t regionEnable
= MPU_RASR_ENABLE
;
136 static const uint32_t regionSizeAndAttributes
= regionReadWrite
| regionSizeAt4GB
| regionEnable
;
137 uint32_t regionIndex
= STACK_SIZE
? getHighestMPUDataRegionIndex() - 1 : getHighestMPUDataRegionIndex();
139 prepareToAccessMPURegion(regionIndex
);
140 setMPURegionAddress(regionToStartAtAddress0
);
141 setMPURegionAttributeAndSize(regionSizeAndAttributes
);
145 extern "C" int __real__read(int file
, char *ptr
, int len
);
146 extern "C" int __wrap__read(int file
, char *ptr
, int len
)
148 if (MRI_SEMIHOST_STDIO
&& file
< 3)
149 return __mriNewlib_SemihostRead(file
, ptr
, len
);
150 return __real__read(file
, ptr
, len
);
154 extern "C" int __real__write(int file
, char *ptr
, int len
);
155 extern "C" int __wrap__write(int file
, char *ptr
, int len
)
157 if (MRI_SEMIHOST_STDIO
&& file
< 3)
158 return __mriNewlib_SemihostWrite(file
, ptr
, len
);
159 return __real__write(file
, ptr
, len
);
163 extern "C" int __real__isatty(int file
);
164 extern "C" int __wrap__isatty(int file
)
166 /* Hardcoding the stdin/stdout/stderr handles to be interactive tty devices, unlike mbed.ar */
169 return __real__isatty(file
);
173 extern "C" int __wrap_semihost_connected(void)
175 /* MRI makes it look like there is no mbed interface attached since it disables the JTAG portion but MRI does
176 support some of the mbed semihost calls when it is running so force it to return -1, indicating that the
177 interface is attached. */
183 extern "C" void abort(void)
192 extern "C" void __cxa_pure_virtual(void)
198 /* Trap calls to malloc/free/realloc in ISR. */
199 extern "C" void __malloc_lock(void)
201 if (__get_IPSR() != 0)
205 extern "C" void __malloc_unlock(void)
210 /* Turn off the errno macro and use actual external global variable instead. */
214 static int doesHeapCollideWithStack(unsigned int newHeap
);
216 /* Dynamic memory allocation related syscalls. */
217 extern "C" caddr_t
_sbrk(int incr
)
219 static unsigned char* heap
= (unsigned char*)&__end__
;
220 unsigned char* prev_heap
= heap
;
221 unsigned char* new_heap
= heap
+ incr
;
223 if (doesHeapCollideWithStack((unsigned int)new_heap
))
230 return (caddr_t
) prev_heap
;
233 static int doesHeapCollideWithStack(unsigned int newHeap
)
235 return ((newHeap
>= __get_MSP()) ||
236 (STACK_SIZE
&& newHeap
>= g_maximumHeapAddress
));
240 /* Optional functionality which will tag each heap allocation with the caller's return address. */
243 const unsigned int* __smoothieHeapBase
= &__end__
;
245 extern "C" void* __real_malloc(size_t size
);
246 extern "C" void* __real_realloc(void* ptr
, size_t size
);
247 extern "C" void __real_free(void* ptr
);
249 static void setTag(void* pv
, unsigned int tag
);
250 static unsigned int* footerForChunk(void* pv
);
251 static unsigned int* headerForChunk(void* pv
);
252 static unsigned int sizeOfChunk(unsigned int* pHeader
);
253 static int isChunkInUse(void* pv
);
255 extern "C" __attribute__((naked
)) void __wrap_malloc(size_t size
)
265 extern "C" void* mallocWithTag(size_t size
, unsigned int tag
)
267 void* p
= __real_malloc(size
+ sizeof(tag
));
268 if (!p
&& __smoothieHeapBase
)
274 static void setTag(void* pv
, unsigned int tag
)
276 unsigned int* pFooter
= footerForChunk(pv
);
280 static unsigned int* footerForChunk(void* pv
)
282 unsigned int* pHeader
= headerForChunk(pv
);
283 unsigned int size
= sizeOfChunk(pHeader
);
284 return (unsigned int*)(void*)((char*)pHeader
+ size
);
287 static unsigned int* headerForChunk(void* pv
)
289 // Header is allocated two words (8 bytes) before the publicly returned allocation chunk address.
290 unsigned int* p
= (unsigned int*)pv
;
294 static unsigned int sizeOfChunk(unsigned int* pHeader
)
296 /* Remove previous chunk in use flag. */
297 return pHeader
[1] & ~1;
300 extern "C" __attribute__((naked
)) void __wrap_realloc(void* ptr
, size_t size
)
310 extern "C" void* reallocWithTag(void* ptr
, size_t size
, unsigned int tag
)
312 void* p
= __real_realloc(ptr
, size
+ sizeof(tag
));
319 extern "C" void __wrap_free(void* ptr
)
321 if (!isChunkInUse(ptr
))
326 static int isChunkInUse(void* pv
)
328 unsigned int* pFooter
= footerForChunk(pv
);
329 return pFooter
[1] & 1;
332 __attribute__((naked
)) void* operator new(size_t size
)
345 // This line never executes but silences no return value warning from compiler.
351 /* Wrap memory allocation routines to make sure that they aren't being called from interrupt handler. */
352 static void breakOnHeapOpFromInterruptHandler(void)
354 if (__get_IPSR() != 0)
358 extern "C" void* __real_malloc(size_t size
);
359 extern "C" void* __wrap_malloc(size_t size
)
361 breakOnHeapOpFromInterruptHandler();
362 return __real_malloc(size
);
366 extern "C" void* __real_realloc(void* ptr
, size_t size
);
367 extern "C" void* __wrap_realloc(void* ptr
, size_t size
)
369 breakOnHeapOpFromInterruptHandler();
370 return __real_realloc(ptr
, size
);
374 extern "C" void __real_free(void* ptr
);
375 extern "C" void __wrap_free(void* ptr
)
377 breakOnHeapOpFromInterruptHandler();