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
);
52 configureStackSizeLimit(STACK_SIZE
);
54 if (WRITE_BUFFER_DISABLE
) {
56 configureMpuRegionToAccessAllMemoryWithNoCaching();
60 __mriInit(MRI_INIT_PARAMETERS
);
61 if (MRI_BREAK_ON_INIT
)
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
;
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
);
79 MemoryPool
_AHB0_stack(&__AHB0_dyn_start
, &__AHB0_end
- &__AHB0_dyn_start
);
80 MemoryPool
_AHB1_stack(&__AHB1_dyn_start
, &__AHB1_end
- &__AHB1_dyn_start
);
85 // MemoryPool init done
88 mainReturnValue
= main();
89 exit(mainReturnValue
);
92 static __attribute__((naked
)) void fillUnusedRAM(void)
97 // Fill 2 words (8 bytes) at a time with 0xdeadbeef.
98 " ldr r2, =__FillStart\n"
100 " movt r0, #0xdead\n"
102 // Don't fill past current stack pointer value.
106 " strd r0, r1, [r2], #8\n"
113 static void configureStackSizeLimit(unsigned int stackSizeLimit
)
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
);
120 static unsigned int alignTo32Bytes(unsigned int value
)
122 return (value
+ 31) & ~31;
125 static void configureMpuToCatchStackOverflowIntoHeap(unsigned int maximumHeapAddress
)
127 #define MPU_REGION_SIZE_OF_32_BYTES ((5-1) << MPU_RASR_SIZE_SHIFT) // 2^5 = 32 bytes.
129 prepareToAccessMPURegion(getHighestMPUDataRegionIndex());
130 setMPURegionAddress(maximumHeapAddress
);
131 setMPURegionAttributeAndSize(MPU_REGION_SIZE_OF_32_BYTES
| MPU_RASR_ENABLE
);
132 enableMPUWithDefaultMemoryMap();
135 static void configureMpuRegionToAccessAllMemoryWithNoCaching(void)
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();
144 prepareToAccessMPURegion(regionIndex
);
145 setMPURegionAddress(regionToStartAtAddress0
);
146 setMPURegionAttributeAndSize(regionSizeAndAttributes
);
150 extern "C" int __real__read(int file
, char *ptr
, int len
);
151 extern "C" int __wrap__read(int file
, char *ptr
, int len
)
153 if (MRI_SEMIHOST_STDIO
&& file
< 3)
154 return __mriNewlib_SemihostRead(file
, ptr
, len
);
155 return __real__read(file
, ptr
, len
);
159 extern "C" int __real__write(int file
, char *ptr
, int len
);
160 extern "C" int __wrap__write(int file
, char *ptr
, int len
)
162 if (MRI_SEMIHOST_STDIO
&& file
< 3)
163 return __mriNewlib_SemihostWrite(file
, ptr
, len
);
164 return __real__write(file
, ptr
, len
);
168 extern "C" int __real__isatty(int file
);
169 extern "C" int __wrap__isatty(int file
)
171 /* Hardcoding the stdin/stdout/stderr handles to be interactive tty devices, unlike mbed.ar */
174 return __real__isatty(file
);
178 extern "C" int __wrap_semihost_connected(void)
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. */
188 extern "C" void abort(void)
197 extern "C" void __cxa_pure_virtual(void)
203 /* Trap calls to malloc/free/realloc in ISR. */
204 extern "C" void __malloc_lock(void)
206 if (__get_IPSR() != 0)
210 extern "C" void __malloc_unlock(void)
215 /* Turn off the errno macro and use actual external global variable instead. */
219 static int doesHeapCollideWithStack(unsigned int newHeap
);
221 /* Dynamic memory allocation related syscalls. */
222 extern "C" caddr_t
_sbrk(int incr
)
224 static unsigned char *heap
= (unsigned char *)&__end__
;
225 unsigned char *prev_heap
= heap
;
226 unsigned char *new_heap
= heap
+ incr
;
228 if (doesHeapCollideWithStack((unsigned int)new_heap
)) {
230 return (caddr_t
) - 1;
234 return (caddr_t
) prev_heap
;
237 static int doesHeapCollideWithStack(unsigned int newHeap
)
239 return ((newHeap
>= __get_MSP()) ||
240 (STACK_SIZE
&& newHeap
>= g_maximumHeapAddress
));
244 /* Optional functionality which will tag each heap allocation with the caller's return address. */
247 const unsigned int *__smoothieHeapBase
= &__end__
;
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
);
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
);
259 extern "C" __attribute__((naked
)) void __wrap_malloc(size_t size
)
269 extern "C" void *mallocWithTag(size_t size
, unsigned int tag
)
271 void *p
= __real_malloc(size
+ sizeof(tag
));
272 if (!p
&& __smoothieHeapBase
)
278 static void setTag(void *pv
, unsigned int tag
)
280 unsigned int *pFooter
= footerForChunk(pv
);
284 static unsigned int *footerForChunk(void *pv
)
286 unsigned int *pHeader
= headerForChunk(pv
);
287 unsigned int size
= sizeOfChunk(pHeader
);
288 return (unsigned int *)(void *)((char *)pHeader
+ size
);
291 static unsigned int *headerForChunk(void *pv
)
293 // Header is allocated two words (8 bytes) before the publicly returned allocation chunk address.
294 unsigned int *p
= (unsigned int *)pv
;
298 static unsigned int sizeOfChunk(unsigned int *pHeader
)
300 /* Remove previous chunk in use flag. */
301 return pHeader
[1] & ~1;
304 extern "C" __attribute__((naked
)) void __wrap_realloc(void *ptr
, size_t size
)
314 extern "C" void *reallocWithTag(void *ptr
, size_t size
, unsigned int tag
)
316 void *p
= __real_realloc(ptr
, size
+ sizeof(tag
));
323 extern "C" void __wrap_free(void *ptr
)
325 if (!isChunkInUse(ptr
))
330 static int isChunkInUse(void *pv
)
332 unsigned int *pFooter
= footerForChunk(pv
);
333 return pFooter
[1] & 1;
336 __attribute__((naked
)) void *operator new(size_t size
)
349 // This line never executes but silences no return value warning from compiler.
355 /* Wrap memory allocation routines to make sure that they aren't being called from interrupt handler. */
356 static void breakOnHeapOpFromInterruptHandler(void)
358 if (__get_IPSR() != 0)
362 extern "C" void *__real_malloc(size_t size
);
363 extern "C" void *__wrap_malloc(size_t size
)
365 breakOnHeapOpFromInterruptHandler();
366 return __real_malloc(size
);
370 extern "C" void *__real_realloc(void *ptr
, size_t size
);
371 extern "C" void *__wrap_realloc(void *ptr
, size_t size
)
373 breakOnHeapOpFromInterruptHandler();
374 return __real_realloc(ptr
, size
);
378 extern "C" void __real_free(void *ptr
);
379 extern "C" void __wrap_free(void *ptr
)
381 breakOnHeapOpFromInterruptHandler();