Commit | Line | Data |
---|---|---|
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 | ||
24 | static void configureHighestMpuRegionToAccessAllMemoryWithNoCaching(void); | |
60c34c05 AG |
25 | |
26 | extern unsigned int __bss_start__; | |
27 | extern unsigned int __bss_end__; | |
28 | extern "C" int main(void); | |
29 | extern "C" void __libc_init_array(void); | |
30 | extern "C" void exit(int ErrorCode); | |
31 | extern "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 |
56 | static 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 | |
71 | extern "C" int __real__read(int file, char *ptr, int len); | |
72 | extern "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 | ||
80 | extern "C" int __real__write(int file, char *ptr, int len); | |
81 | extern "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 | ||
89 | extern "C" int __real__isatty(int file); | |
90 | extern "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 | ||
99 | extern "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 | ||
109 | extern "C" void abort(void) | |
110 | { | |
111 | if (MRI_ENABLE) | |
112 | __debugbreak(); | |
113 | ||
114 | exit(1); | |
115 | } | |
116 | ||
117 | ||
118 | extern "C" void __cxa_pure_virtual(void) | |
119 | { | |
120 | abort(); | |
121 | } | |
122 | ||
123 | ||
124 | extern "C" int __aeabi_unwind_cpp_pr0(int state, void* controlBlock, void* context) | |
125 | { | |
126 | abort(); | |
127 | } | |
128 | ||
129 | ||
130 | extern "C" int __aeabi_unwind_cpp_pr1(int state, void* controlBlock, void* context) | |
131 | { | |
132 | abort(); | |
133 | } | |
134 | ||
135 | ||
136 | extern "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. */ | |
142 | extern "C" void __malloc_lock(void) | |
143 | { | |
144 | if (__get_IPSR() != 0) | |
145 | __debugbreak(); | |
146 | } | |
147 | ||
148 | extern "C" void __malloc_unlock(void) | |
149 | { | |
150 | } | |
151 | ||
152 | ||
153 | /* Linker defined symbol to be used by sbrk for where dynamically heap should start. */ | |
154 | extern "C" unsigned int __HeapBase; | |
155 | ||
156 | /* Turn off the errno macro and use actual external global variable instead. */ | |
157 | #undef errno | |
158 | extern int errno; | |
159 | ||
160 | /* Dynamic memory allocation related syscalls. */ | |
161 | extern "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 | ||
180 | const unsigned int* __smoothieHeapBase = &__HeapBase; | |
181 | ||
182 | extern "C" void* __real_malloc(size_t size); | |
183 | extern "C" void* __real_realloc(void* ptr, size_t size); | |
184 | ||
185 | static void setTag(void* pv, unsigned int tag); | |
186 | static unsigned int* footerForChunk(void* pv); | |
187 | static unsigned int* headerForChunk(void* pv); | |
188 | static unsigned int sizeOfChunk(unsigned int* pHeader); | |
189 | ||
190 | extern "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 | ||
200 | extern "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 | ||
209 | static void setTag(void* pv, unsigned int tag) | |
210 | { | |
211 | unsigned int* pFooter = footerForChunk(pv); | |
212 | *pFooter = tag; | |
213 | } | |
214 | ||
215 | static 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 | ||
222 | static 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 | ||
229 | static unsigned int sizeOfChunk(unsigned int* pHeader) | |
230 | { | |
231 | /* Remove previous chunk in use flag. */ | |
232 | return pHeader[1] & ~1; | |
233 | } | |
234 | ||
235 | extern "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 | ||
245 | extern "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 |