Commit | Line | Data |
---|---|---|
6c79da43 | 1 | /* Copyright 2012 Adam Green (http://mbed.org/users/AdamGreen/)\r |
4cff3ded AW |
2 | \r |
3 | Licensed under the Apache License, Version 2.0 (the "License");\r | |
4 | you may not use this file except in compliance with the License.\r | |
5 | You may obtain a copy of the License at\r | |
6 | \r | |
7 | http://www.apache.org/licenses/LICENSE-2.0\r | |
8 | \r | |
9 | Unless required by applicable law or agreed to in writing, software\r | |
10 | distributed under the License is distributed on an "AS IS" BASIS,\r | |
11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r | |
12 | See the License for the specific language governing permissions and\r | |
13 | limitations under the License.\r | |
14 | */\r | |
15 | /* System calls called out as overrideable in newlib documentation which weren't implemented follow in this list\r | |
16 | with reason:\r | |
17 | \r | |
18 | environ Not required. getenv() and setenv() can be used without providing an override as there is a default\r | |
19 | _execve Standard C APIs implemented by newlib don't end up calling this function. Implemented _system\r | |
20 | instead.\r | |
21 | _fork Standard C APIs implemented by newlib don't end up calling this function. Implemented _system\r | |
22 | instead.\r | |
23 | _link This is a POSIX routine and while newlib will call it for the standard C rename() function, this\r | |
24 | particular routine is overridden in mbed.ar where it just returns -1.\r | |
25 | _stat This is a system API and not part of the C standard. It doesn't appear to be required for mbed.\r | |
26 | _times Appears to be a system API and not part of the C standard. Not called from standard APIs.\r | |
27 | _unlink This is a POSIX routine. newlib will call it for standard C remove(), this particular API is\r | |
28 | already overidden by mbed.ar\r | |
29 | */\r | |
30 | #include <reent.h>\r | |
31 | #include <errno.h>\r | |
32 | #include <stdlib.h> /* abort */\r | |
33 | #include <sys/types.h>\r | |
34 | #include <sys/stat.h>\r | |
35 | #include <sys/_default_fcntl.h>\r | |
36 | #include "LPC17xx.h" /* for _get_*SP() from core_cm3.h*/\r | |
37 | #include "mbedsys.h" /* for _sys_*() functions implemented in mbed/capi.ar */\r | |
38 | #include "error.h" /* for error() panic routine */\r | |
ee8a0081 | 39 | #include "mri.h"\r |
4cff3ded AW |
40 | \r |
41 | \r | |
42 | #undef errno\r | |
43 | extern int errno;\r | |
44 | \r | |
45 | \r | |
46 | /* Flag used to track whether the stdin/stdout/stderr handles have been opened yet */\r | |
47 | static int g_StandardHandlesOpened = 0;\r | |
48 | \r | |
49 | \r | |
50 | /* Open the stdin/stdout/stderr handles */\r | |
13e4a3f9 | 51 | extern "C" void __GCC4MBEDOpenStandardHandles(void)\r |
4cff3ded AW |
52 | {\r |
53 | /* Open stdin/stdout/stderr */\r | |
54 | _sys_open("/stdin", OPENMODE_R);\r | |
55 | _sys_open("/stdout", OPENMODE_W);\r | |
56 | _sys_open("/stderr", OPENMODE_W);\r | |
57 | \r | |
58 | g_StandardHandlesOpened = 1;\r | |
59 | } \r | |
60 | \r | |
61 | \r | |
62 | extern "C" int _kill(int pid, int sig)\r | |
63 | {\r | |
64 | /* Avoid warnings */\r | |
65 | (void)pid;\r | |
66 | (void)sig;\r | |
67 | \r | |
68 | errno = EINVAL;\r | |
69 | return -1;\r | |
70 | }\r | |
71 | \r | |
72 | extern "C" void _exit(int status)\r | |
73 | {\r | |
74 | /* Call the mbed version of exit found in capi.ar */\r | |
75 | exit(status);\r | |
76 | }\r | |
77 | \r | |
78 | extern "C" int _getpid(void)\r | |
79 | {\r | |
80 | return 1;\r | |
81 | }\r | |
82 | \r | |
83 | \r | |
84 | extern char _end; /* Defined by the linker */\r | |
85 | static char *heap_end;\r | |
86 | \r | |
87 | static char* get_stack_top(void)\r | |
88 | {\r | |
89 | return (char*) __get_MSP();\r | |
90 | }\r | |
91 | \r | |
92 | extern "C" caddr_t _sbrk(int incr)\r | |
93 | {\r | |
94 | char *prev_heap_end;\r | |
95 | if (heap_end == 0) {\r | |
96 | heap_end = &_end;\r | |
97 | }\r | |
98 | prev_heap_end = heap_end;\r | |
99 | if (heap_end + incr > get_stack_top()) {\r | |
100 | \r | |
101 | abort();\r | |
102 | }\r | |
103 | heap_end += incr;\r | |
104 | return (caddr_t) prev_heap_end;\r | |
105 | }\r | |
106 | \r | |
107 | extern "C" int _open(const char *name, int flags, int mode) \r | |
108 | {\r | |
109 | int OpenMode = 0;\r | |
110 | \r | |
111 | (void)mode;\r | |
112 | \r | |
113 | /* Convert from newlib flags to mbed openmode */\r | |
114 | if (flags & O_RDWR)\r | |
115 | {\r | |
116 | OpenMode |= OPENMODE_PLUS;\r | |
117 | }\r | |
118 | if (flags & O_TRUNC)\r | |
119 | {\r | |
120 | OpenMode |= OPENMODE_W;\r | |
121 | }\r | |
122 | if (flags & O_APPEND)\r | |
123 | {\r | |
124 | OpenMode |= OPENMODE_A;\r | |
125 | }\r | |
126 | \r | |
127 | return _sys_open(name, OpenMode);\r | |
128 | }\r | |
129 | \r | |
130 | extern "C" int _close(int file)\r | |
131 | {\r | |
132 | return _sys_close(file);\r | |
133 | }\r | |
134 | \r | |
135 | extern "C" int _isatty(int file)\r | |
136 | {\r | |
137 | /* Hardcoding the stdin/stdout/stderr handles to be interactive tty devices, unlike mbed.ar */\r | |
138 | if (file < 3)\r | |
139 | {\r | |
140 | return 1;\r | |
141 | }\r | |
142 | \r | |
143 | return _sys_istty(file);\r | |
144 | }\r | |
145 | \r | |
146 | /* TODO: Remove this later when _lseek no longer requires it */\r | |
147 | static unsigned short _crc16(const unsigned char* pBuffer, size_t BufferSizeInBytes)\r | |
148 | {\r | |
149 | unsigned short CRC = 0;\r | |
150 | \r | |
151 | while (BufferSizeInBytes--)\r | |
152 | {\r | |
153 | unsigned short Byte = (unsigned short)*pBuffer++;\r | |
154 | int i;\r | |
155 | \r | |
156 | for (i = 0 ; i < 8 ; i++)\r | |
157 | {\r | |
158 | unsigned short Value = (Byte ^ CRC) & 1;\r | |
159 | CRC >>= 1;\r | |
160 | if (Value)\r | |
161 | {\r | |
162 | CRC ^= 0xA001;\r | |
163 | }\r | |
164 | Byte >>= 1;\r | |
165 | }\r | |
166 | }\r | |
167 | \r | |
168 | return ~CRC;\r | |
169 | }\r | |
170 | \r | |
171 | extern "C" int _lseek(int file, int ptr, int dir) \r | |
172 | {\r | |
173 | /* Function pointer type for the FileHandle::lseek() method */\r | |
174 | typedef int (*lseekMethod)(void* pThis, int ptr, int dir);\r | |
175 | static const unsigned short ExpectedSysSeekCRC = 0xDFC0;\r | |
176 | static lseekMethod*** pppFileHandles = NULL;\r | |
177 | lseekMethod** ppFileHandle;\r | |
178 | lseekMethod* pFileHandleVTable;\r | |
179 | lseekMethod FileHandle_lseekMethod;\r | |
180 | \r | |
181 | /* When file is set to 0, 1, or 2 then the file is actually a standard I/O stream so just return 0 since they\r | |
182 | don't really support seeking and this is what _sys_seek() does as well */\r | |
183 | if (file < 3)\r | |
184 | {\r | |
185 | return 0;\r | |
186 | }\r | |
187 | \r | |
188 | /* Find the location of the filehandles array if we haven't already */\r | |
189 | if (!pppFileHandles)\r | |
190 | {\r | |
191 | /* TODO: This code is pretty hacky but it is the only way I can get things to work with mbed.ar at this time.\r | |
192 | If the mbed crew could make a small change to their library such that they exposed something equivalent\r | |
193 | to _sys_lseek in addition to their _sys_seek then both this _lseek function and their _sys_seek could \r | |
194 | call it to perform seeks using any seek direction (whence) value */\r | |
195 | unsigned short* pSysSeek;\r | |
196 | unsigned short CRC;\r | |
197 | \r | |
198 | /* Grab a pointer to where the _sys_seek code ends up being loaded for this program */\r | |
199 | pSysSeek = (unsigned short*)((unsigned int)_sys_seek & ~1);\r | |
200 | \r | |
201 | /* Perform a CRC over the first 40 bytes which contain PC-relative code for the _sys_seek function to\r | |
202 | make sure that it hasn't changed from when I figured out the location of the pointer used for\r | |
203 | dereferencing into the 16 element filehandles static array from stdio.cpp */\r | |
204 | CRC = _crc16((unsigned char*)pSysSeek, 40);\r | |
205 | if (ExpectedSysSeekCRC != CRC)\r | |
206 | {\r | |
207 | error("RIP: _sys_seek() in mbed.ar has been modified\r\n"\r | |
208 | " and _lseek in gcc4mbed/syscalls.c needs to be updated\r\n");\r | |
209 | }\r | |
210 | \r | |
211 | /* I know that the pointer for the filehandles array is stored as a literal 20 shorts after the beginning of the \r | |
212 | _sys_seek() function */\r | |
213 | pppFileHandles = (lseekMethod***)*(void**)(void*)(pSysSeek + 20);\r | |
214 | }\r | |
215 | \r | |
216 | \r | |
217 | /* Find the pointer to the FileHandle object representing this file */\r | |
218 | ppFileHandle = pppFileHandles[file - 3];\r | |
219 | if (!ppFileHandle)\r | |
220 | {\r | |
221 | /* The file handle isn't valid */\r | |
222 | return -1;\r | |
223 | }\r | |
224 | \r | |
225 | /* The vtable for this FileHandle object will be stored in the first 4-byte word of the object */\r | |
226 | pFileHandleVTable = *ppFileHandle;\r | |
227 | \r | |
228 | /* The fifth element of this vtable is the pointer to the lseek method */\r | |
229 | FileHandle_lseekMethod = pFileHandleVTable[4];\r | |
230 | \r | |
231 | /* Finally call into the file handle object's seek method */\r | |
232 | return FileHandle_lseekMethod(ppFileHandle, ptr, dir);\r | |
233 | }\r | |
234 | \r | |
235 | extern "C" int _read(int file, char *ptr, int len)\r | |
236 | {\r | |
237 | int BytesNotRead;\r | |
238 | \r | |
239 | /* Open stdin/stdout/stderr if needed */\r | |
6c79da43 | 240 | if (MRI_SEMIHOST_STDIO && file < 3)\r |
3c132bd0 | 241 | {\r |
6c79da43 | 242 | return __mriNewlib_SemihostRead(file, ptr, len);\r |
3c132bd0 AW |
243 | }\r |
244 | else if (!g_StandardHandlesOpened && file < 3)\r | |
4cff3ded | 245 | {\r |
13e4a3f9 | 246 | __GCC4MBEDOpenStandardHandles();\r |
4cff3ded AW |
247 | }\r |
248 | \r | |
249 | /* Call the function in mbed.ar and let it handle the read */\r | |
250 | BytesNotRead = _sys_read(file, (unsigned char*)ptr, len, 0);\r | |
251 | \r | |
252 | /* EOF is indicated by setting the most significant bit so mask it off */\r | |
253 | BytesNotRead &= 0x7FFFFFFF;\r | |
254 | \r | |
255 | /* The mbed version of the function returns bytes not read and newlib wants bytes read count */\r | |
256 | return len - BytesNotRead;\r | |
257 | }\r | |
258 | \r | |
259 | extern "C" int _write(int file, char *ptr, int len)\r | |
260 | {\r | |
261 | int BytesNotWritten;\r | |
262 | \r | |
263 | /* Open stdin/stdout/stderr if needed */\r | |
6c79da43 | 264 | if (MRI_SEMIHOST_STDIO && file < 3)\r |
3c132bd0 | 265 | {\r |
6c79da43 | 266 | return __mriNewlib_SemihostWrite(file, ptr, len);\r |
3c132bd0 AW |
267 | }\r |
268 | else if (!g_StandardHandlesOpened && file < 3)\r | |
4cff3ded | 269 | {\r |
13e4a3f9 | 270 | __GCC4MBEDOpenStandardHandles();\r |
4cff3ded AW |
271 | }\r |
272 | \r | |
273 | /* Call the function in mbed.ar and let it handle the writes */\r | |
274 | BytesNotWritten = _sys_write(file, (const unsigned char*)ptr, len, 0);\r | |
275 | \r | |
276 | /* The mbed version of the function returns bytes not written and newlib wants byte written count */\r | |
277 | if (BytesNotWritten >= 0)\r | |
278 | {\r | |
279 | return len - BytesNotWritten;\r | |
280 | }\r | |
281 | else\r | |
282 | {\r | |
283 | /* In this case it did return an error */\r | |
284 | return BytesNotWritten;\r | |
285 | }\r | |
286 | }\r | |
287 | \r | |
288 | extern "C" int _fstat(int file, struct stat *st)\r | |
289 | {\r | |
290 | (void)file;\r | |
291 | \r | |
292 | st->st_mode = S_IFCHR;\r | |
293 | return 0;\r | |
294 | }\r | |
295 | \r | |
296 | extern "C" int _system(const char* pCommand)\r | |
297 | {\r | |
298 | if (NULL == pCommand)\r | |
299 | {\r | |
300 | /* There is no command interpreter on the mbed */\r | |
301 | return 0;\r | |
302 | }\r | |
303 | else\r | |
304 | {\r | |
305 | /* Indicate that command couldn't be executed since there is no command interpreter */\r | |
306 | errno = ENOENT;\r | |
307 | return -1;\r | |
308 | }\r | |
309 | }\r |