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