re-enabling serial
[clinton/Smoothieware.git] / gcc4mbed / src / syscalls.c
CommitLineData
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
43extern int errno;\r
44\r
45\r
46/* Flag used to track whether the stdin/stdout/stderr handles have been opened yet */\r
47static int g_StandardHandlesOpened = 0;\r
48\r
49\r
50/* Open the stdin/stdout/stderr handles */\r
13e4a3f9 51extern "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
62extern "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
72extern "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
78extern "C" int _getpid(void)\r
79{\r
80 return 1;\r
81}\r
82\r
83\r
84extern char _end; /* Defined by the linker */\r
85static char *heap_end;\r
86\r
87static char* get_stack_top(void)\r
88{\r
89 return (char*) __get_MSP();\r
90}\r
91\r
92extern "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
107extern "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
130extern "C" int _close(int file)\r
131{\r
132 return _sys_close(file);\r
133}\r
134\r
135extern "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
147static 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
171extern "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
235extern "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
259extern "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
288extern "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
296extern "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