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