1 /* Copyright 2012 Adam Green (http://mbed.org/users/AdamGreen/)
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
7 http://www.apache.org/licenses/LICENSE-2.0
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.
15 /* System calls called out as overrideable in newlib documentation which weren't implemented follow in this list
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
21 _fork Standard C APIs implemented by newlib don't end up calling this function. Implemented _system
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
32 #include <stdlib.h> /* abort */
33 #include <sys/types.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 */
46 /* Flag used to track whether the stdin/stdout/stderr handles have been opened yet */
47 static int g_StandardHandlesOpened
= 0;
50 /* Open the stdin/stdout/stderr handles */
51 extern "C" void __GCC4MBEDOpenStandardHandles(void)
53 /* Open stdin/stdout/stderr */
54 _sys_open("/stdin", OPENMODE_R
);
55 _sys_open("/stdout", OPENMODE_W
);
56 _sys_open("/stderr", OPENMODE_W
);
58 g_StandardHandlesOpened
= 1;
62 extern "C" int _kill(int pid
, int sig
)
72 extern "C" void _exit(int status
)
74 /* Call the mbed version of exit found in capi.ar */
78 extern "C" int _getpid(void)
84 extern char _end
; /* Defined by the linker */
85 static char *heap_end
;
87 static char* get_stack_top(void)
89 return (char*) __get_MSP();
92 extern "C" caddr_t
_sbrk(int incr
)
98 prev_heap_end
= heap_end
;
99 if (heap_end
+ incr
> get_stack_top()) {
104 return (caddr_t
) prev_heap_end
;
107 extern "C" int _open(const char *name
, int flags
, int mode
)
113 /* Convert from newlib flags to mbed openmode */
116 OpenMode
|= OPENMODE_PLUS
;
120 OpenMode
|= OPENMODE_W
;
122 if (flags
& O_APPEND
)
124 OpenMode
|= OPENMODE_A
;
127 return _sys_open(name
, OpenMode
);
130 extern "C" int _close(int file
)
132 return _sys_close(file
);
135 extern "C" int _isatty(int file
)
137 /* Hardcoding the stdin/stdout/stderr handles to be interactive tty devices, unlike mbed.ar */
143 return _sys_istty(file
);
146 /* TODO: Remove this later when _lseek no longer requires it */
147 static unsigned short _crc16(const unsigned char* pBuffer
, size_t BufferSizeInBytes
)
149 unsigned short CRC
= 0;
151 while (BufferSizeInBytes
--)
153 unsigned short Byte
= (unsigned short)*pBuffer
++;
156 for (i
= 0 ; i
< 8 ; i
++)
158 unsigned short Value
= (Byte
^ CRC
) & 1;
171 extern "C" int _lseek(int file
, int ptr
, int dir
)
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
;
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 */
188 /* Find the location of the filehandles array if we haven't already */
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
;
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);
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
)
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");
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);
217 /* Find the pointer to the FileHandle object representing this file */
218 ppFileHandle
= pppFileHandles
[file
- 3];
221 /* The file handle isn't valid */
225 /* The vtable for this FileHandle object will be stored in the first 4-byte word of the object */
226 pFileHandleVTable
= *ppFileHandle
;
228 /* The fifth element of this vtable is the pointer to the lseek method */
229 FileHandle_lseekMethod
= pFileHandleVTable
[4];
231 /* Finally call into the file handle object's seek method */
232 return FileHandle_lseekMethod(ppFileHandle
, ptr
, dir
);
235 extern "C" int _read(int file
, char *ptr
, int len
)
239 /* Open stdin/stdout/stderr if needed */
240 if (MRI_SEMIHOST_STDIO
&& file
< 3)
242 return __mriNewlib_SemihostRead(file
, ptr
, len
);
244 else if (!g_StandardHandlesOpened
&& file
< 3)
246 __GCC4MBEDOpenStandardHandles();
249 /* Call the function in mbed.ar and let it handle the read */
250 BytesNotRead
= _sys_read(file
, (unsigned char*)ptr
, len
, 0);
252 /* EOF is indicated by setting the most significant bit so mask it off */
253 BytesNotRead
&= 0x7FFFFFFF;
255 /* The mbed version of the function returns bytes not read and newlib wants bytes read count */
256 return len
- BytesNotRead
;
259 extern "C" int _write(int file
, char *ptr
, int len
)
263 /* Open stdin/stdout/stderr if needed */
264 if (MRI_SEMIHOST_STDIO
&& file
< 3)
266 return __mriNewlib_SemihostWrite(file
, ptr
, len
);
268 else if (!g_StandardHandlesOpened
&& file
< 3)
270 __GCC4MBEDOpenStandardHandles();
273 /* Call the function in mbed.ar and let it handle the writes */
274 BytesNotWritten
= _sys_write(file
, (const unsigned char*)ptr
, len
, 0);
276 /* The mbed version of the function returns bytes not written and newlib wants byte written count */
277 if (BytesNotWritten
>= 0)
279 return len
- BytesNotWritten
;
283 /* In this case it did return an error */
284 return BytesNotWritten
;
288 extern "C" int _fstat(int file
, struct stat
*st
)
292 st
->st_mode
= S_IFCHR
;
296 extern "C" int _system(const char* pCommand
)
298 if (NULL
== pCommand
)
300 /* There is no command interpreter on the mbed */
305 /* Indicate that command couldn't be executed since there is no command interpreter */