2 // Support files for GNU libc. Files in the system namespace go here.
3 // Files in the C namespace (ie those that do not start with an underscore) go in .c
13 #include <sys/times.h>
21 #include "../uart/uart.h"
22 #include "../usbser/usbser.h"
23 #include "../rtc/rtc.h"
24 #include "../fatfs/ff.h"
29 int _mkdir _PARAMS ((const char *, mode_t));
30 int _chmod _PARAMS ((const char *, mode_t));
31 int _read _PARAMS ((int, char *, int));
32 int _lseek _PARAMS ((int, int, int));
33 int _write _PARAMS ((int, const char *, int));
34 int _open _PARAMS ((const char *, int, ...));
35 int _close _PARAMS ((int));
36 int _kill _PARAMS ((int, int));
37 void _exit _PARAMS ((int));
38 int _getpid _PARAMS ((int));
39 caddr_t _sbrk _PARAMS ((int));
40 int _fstat _PARAMS ((int, struct stat *));
41 int _stat _PARAMS ((const char *, struct stat *));
42 int _link _PARAMS ((void));
43 int _unlink _PARAMS ((const char *));
44 void _raise _PARAMS ((void));
45 int _gettimeofday _PARAMS ((struct timeval *, struct timezone *));
46 clock_t _times _PARAMS ((struct tms *));
47 int isatty _PARAMS ((int));
48 int _rename _PARAMS ((const char *, const char *));
49 int _system _PARAMS ((const char *));
50 void _sync _PARAMS ((void));
51 void syscallsInit _PARAMS ((void));
53 int rename _PARAMS ((const char *, const char *));
55 static int set_errno _PARAMS ((int));
56 static time_t fatfs_time_to_timet _PARAMS ((FILINFO *));
57 static int remap_handle _PARAMS ((int));
58 static int findslot _PARAMS ((int));
61 // Register name faking - works in collusion with the linker
63 register char *stack_ptr asm ("sp");
66 // Following is copied from libc/stdio/local.h to check std streams
68 extern void _EXFUN (__sinit,( struct _reent *));
70 #define CHECK_INIT(ptr) \
73 if ((ptr) && !(ptr)->__sdidinit) \
79 // Adjust our internal handles to stay away from std* handles
81 #define FILE_HANDLE_OFFSET (0x20)
83 #define MONITOR_STDIN 0
84 #define MONITOR_STDOUT 1
85 #define MONITOR_STDERR 2
86 #define MONITOR_UART0 3
87 #define MONITOR_UART1 4
89 #define MONITOR_FATFS 6
106 #define MAX_OPEN_FILES 10
107 static openFiles_t openfiles [MAX_OPEN_FILES];
109 static int findslot (int fh)
112 static int lastfh = -1;
114 if ((fh != -1) && (fh == lastfh))
117 for (slot = 0; slot < MAX_OPEN_FILES; slot++)
118 if (openfiles [slot].handle == fh)
127 // Function to convert std(in|out|err) handles to internal versions.
129 static int remap_handle (int fh)
133 if (fh == STDIN_FILENO)
134 return MONITOR_STDIN;
135 if (fh == STDOUT_FILENO)
136 return MONITOR_STDOUT;
137 if (fh == STDERR_FILENO)
138 return MONITOR_STDERR;
140 return fh - FILE_HANDLE_OFFSET;
143 static int remap_fatfs_errors (FRESULT f)
147 case FR_NO_FILE : errno = ENOENT; break;
148 case FR_NO_PATH : errno = ENOENT; break;
149 case FR_INVALID_NAME : errno = EINVAL; break;
150 case FR_INVALID_DRIVE : errno = ENODEV; break;
151 case FR_DENIED : errno = EACCES; break;
152 case FR_EXIST : errno = EEXIST; break;
153 case FR_NOT_READY : errno = EIO; break;
154 case FR_WRITE_PROTECTED : errno = EACCES; break;
155 case FR_RW_ERROR : errno = EIO; break;
156 case FR_NOT_ENABLED : errno = EIO; break;
157 case FR_NO_FILESYSTEM : errno = EIO; break;
158 case FR_INVALID_OBJECT : errno = EBADF; break;
159 default : errno = EIO; break;
165 static time_t fatfs_time_to_timet (FILINFO *f)
169 tm.tm_sec = (f->ftime & 0x001f) << 1;
170 tm.tm_min = (f->ftime & 0x07e0) >> 5;
171 tm.tm_hour = (f->ftime & 0xf800) >> 11;
172 tm.tm_mday = (f->fdate & 0x001f);
173 tm.tm_mon = ((f->fdate & 0x01e0) >> 5) - 1;
174 tm.tm_year = ((f->fdate & 0xfe00) >> 9) + 80;
180 static int set_errno (int errval)
187 void syscallsInit (void)
190 static int initialized = 0;
197 __builtin_memset (openfiles, 0, sizeof (openfiles));
199 for (slot = 0; slot < MAX_OPEN_FILES; slot++)
200 openfiles [slot].handle = -1;
202 openfiles [0].handle = MONITOR_STDIN;
203 openfiles [1].handle = MONITOR_STDOUT;
204 openfiles [2].handle = MONITOR_STDERR;
207 int _mkdir (const char *path, mode_t mode __attribute__ ((unused)))
211 if ((f = f_mkdir (path)) != FR_OK)
212 return remap_fatfs_errors (f);
217 int _chmod (const char *path, mode_t mode)
221 if ((f = f_chmod (path, (mode & S_IWUSR) ? 0 : AM_RDO, AM_RDO)) != FR_OK)
222 return remap_fatfs_errors (f);
227 int _read (int fd, char *ptr, int len)
232 portTickType xBlockTime;
233 int bytesUnRead = -1;
235 if ((slot = findslot (fh = remap_handle (fd))) == MAX_OPEN_FILES)
236 return set_errno (EBADF);
238 if (openfiles [slot].flags & O_WRONLY)
239 return set_errno (EBADF);
241 xBlockTime = (openfiles [slot].flags & O_NONBLOCK) ? 0 : portMAX_DELAY;
247 for (i = 0; i < len; i++)
248 if (!uartGetChar (0, (signed portCHAR *) ptr++, xBlockTime))
251 bytesUnRead = len - i;
255 case MONITOR_STDOUT :
256 case MONITOR_STDERR :
261 for (i = 0; i < len; i++)
262 if (!uartGetChar (0, (signed portCHAR *) ptr++, xBlockTime))
265 bytesUnRead = len - i;
271 for (i = 0; i < len; i++)
272 if (!uartGetChar (1, (signed portCHAR *) ptr++, xBlockTime))
275 bytesUnRead = len - i;
281 for (i = 0; i < len; i++)
282 if (!usbserGetChar ((signed portCHAR *) ptr++, xBlockTime))
285 bytesUnRead = len - i;
291 if (openfiles [slot].fatfsFCB)
296 if ((f = f_read (openfiles [slot].fatfsFCB, ptr, len, &fatfsBytesRead)) != FR_OK)
297 return remap_fatfs_errors (f);
299 bytesUnRead = len - fatfsBytesRead;
308 openfiles [slot].pos += len - bytesUnRead;
310 return len - bytesUnRead;
313 int _lseek (int fd, int ptr, int dir)
317 FRESULT f = FR_INVALID_OBJECT;
319 if (((slot = findslot (fh = remap_handle (fd))) == MAX_OPEN_FILES) || !openfiles [slot].fatfsFCB)
320 return set_errno (EBADF);
323 f = f_lseek (openfiles [slot].fatfsFCB, ptr);
324 else if (dir == SEEK_CUR)
325 f = f_lseek (openfiles [slot].fatfsFCB, openfiles [slot].fatfsFCB->fptr + ptr);
326 else if (dir == SEEK_END)
327 f = f_lseek (openfiles [slot].fatfsFCB, openfiles [slot].fatfsFCB->fsize + ptr);
330 return remap_fatfs_errors (f);
332 return openfiles [slot].pos = openfiles [slot].fatfsFCB->fptr;
335 int _write (int fd, const char *ptr, int len)
340 portTickType xBlockTime;
341 int bytesUnWritten = -1;
343 if ((slot = findslot (fh = remap_handle (fd))) == MAX_OPEN_FILES)
344 return set_errno (EBADF);
346 if (openfiles [slot].flags & O_RDONLY)
347 return set_errno (EBADF);
349 xBlockTime = (openfiles [slot].flags & O_NONBLOCK) ? 0 : portMAX_DELAY;
356 case MONITOR_STDOUT :
357 case MONITOR_STDERR :
359 for (i = 0; i < len; i++)
362 if (!uartPutChar (0, '\r', xBlockTime))
364 if (!uartPutChar (0, *ptr++, xBlockTime))
368 bytesUnWritten = len - i;
374 for (i = 0; i < len; i++)
375 if (!uartPutChar (0, *ptr++, xBlockTime))
378 bytesUnWritten = len - i;
384 for (i = 0; i < len; i++)
386 #ifdef CFG_CONSOLE_UART1
388 if (!uartPutChar (1, '\r', xBlockTime))
391 if (!uartPutChar (1, *ptr++, xBlockTime))
395 bytesUnWritten = len - i;
401 for (i = 0; i < len; i++)
403 #ifdef CFG_CONSOLE_USB
405 if (!usbserPutChar ('\r', xBlockTime))
408 if (!usbserPutChar (*ptr++, xBlockTime))
412 bytesUnWritten = len - i;
418 if (openfiles [slot].fatfsFCB)
421 U16 fatfsBytesWritten;
423 if ((f = f_write (openfiles [slot].fatfsFCB, ptr, len, &fatfsBytesWritten)) != FR_OK)
424 return remap_fatfs_errors (f);
426 bytesUnWritten = len - fatfsBytesWritten;
429 return set_errno (EBADF);
434 if (bytesUnWritten == -1 || bytesUnWritten == len)
437 openfiles [slot].pos += len - bytesUnWritten;
439 return len - bytesUnWritten;
442 int _open (const char *path, int flags, ...)
447 if ((slot = findslot (-1)) == MAX_OPEN_FILES)
448 return set_errno (ENFILE);
450 if (flags & O_APPEND)
453 if (!__builtin_strcmp (path, "/dev/uart0"))
455 else if (!__builtin_strcmp (path, "/dev/uart1"))
457 else if (!__builtin_strcmp (path, "/dev/usb"))
461 U8 fatfsFlags = FA_OPEN_EXISTING;
465 // FA_OPEN_EXISTING Opens the file. The function fails if the file is not existing. (Default)
466 // FA_OPEN_ALWAYS Opens the file, if it is existing. If not, the function creates the new file.
467 // FA_CREATE_NEW Creates a new file. The function fails if the file is already existing.
468 // FA_CREATE_ALWAYS Creates a new file. If the file is existing, it is truncated and overwritten.
470 // O_CREAT If the file does not exist it will be created.
471 // O_EXCL When used with O_CREAT, if the file already exists it is an error and the open() will fail.
472 // O_TRUNC If the file already exists and is a regular file and the open mode allows writing (i.e., is O_RDWR or O_WRONLY) it will be truncated to length 0.
474 if (((flags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC)) && (flags & (O_RDWR | O_WRONLY)))
475 fatfsFlags = FA_CREATE_ALWAYS;
476 else if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
477 fatfsFlags = FA_OPEN_EXISTING;
478 else if ((flags & O_CREAT) == O_CREAT)
479 fatfsFlags = FA_OPEN_ALWAYS;
480 else if ((flags == O_RDONLY) || (flags == O_WRONLY) || (flags == O_RDWR))
481 fatfsFlags = FA_OPEN_EXISTING;
483 return set_errno (EINVAL);
485 if ((flags & O_ACCMODE) == O_RDONLY)
486 fatfsFlags |= FA_READ;
487 else if ((flags & O_ACCMODE) == O_WRONLY)
488 fatfsFlags |= FA_WRITE;
489 else if ((flags & O_ACCMODE) == O_RDWR)
490 fatfsFlags |= (FA_READ | FA_WRITE);
492 return set_errno (EINVAL);
497 if (!openfiles [slot].fatfsFCB)
498 if ((openfiles [slot].fatfsFCB = __builtin_calloc (1, sizeof (FIL))))
499 if ((fh = ((f = f_open (openfiles [slot].fatfsFCB, path, fatfsFlags)) == FR_OK) ? (slot + MONITOR_FATFS) : -1) == -1)
500 return remap_fatfs_errors (f);
505 openfiles [slot].handle = fh;
506 openfiles [slot].pos = 0;
507 openfiles [slot].flags = flags;
510 return fh >= 0 ? (fh + FILE_HANDLE_OFFSET) : -1;
517 if ((slot = findslot (remap_handle (fd))) == MAX_OPEN_FILES)
518 return set_errno (EBADF);
520 openfiles [slot].handle = -1;
522 if (openfiles [slot].fatfsFCB)
526 f = f_close (openfiles [slot].fatfsFCB);
527 free (openfiles [slot].fatfsFCB);
528 openfiles [slot].fatfsFCB = NULL;
531 return remap_fatfs_errors (f);
537 int _kill (int pid __attribute__ ((unused)), int sig __attribute__ ((unused)))
539 return set_errno (ENOTSUP);
542 void _exit (int status)
544 /* There is only one SWI for both _exit and _kill. For _exit, call
545 the SWI with the second argument set to -1, an invalid value for
546 signum, so that the SWI handler can distinguish the two calls.
547 Note: The RDI implementation of _kill throws away both its
560 caddr_t _sbrk (int incr)
562 extern char end asm ("end"); /* Defined by the linker. */
563 extern unsigned long __heap_max;
564 static char *heap_end;
571 prev_heap_end = heap_end;
574 // If FreeRTOS is not running, the stack pointer will be in the SVC region,
575 // and therefore greater than the start of the heap (end of .bss). In this
576 // case, we see if the heap allocation will run past the current stack
577 // pointer, and if so, return ENOMEM (this does not guarantee subsequent
578 // stack operations won't overflow into the heap!).
580 // If FreeRTOS is running, then we define the end of the heap to be the
581 // start of end of the supervisor stack (since FreeRTOS is running, the
582 // system stack, and very little of the supervisor stack space is used).
584 eom = (stack_ptr > & end) ? stack_ptr : (char *) __heap_max;
586 if (heap_end + incr > eom)
594 return (caddr_t) prev_heap_end;
598 // Tihs is a problem. FatFS has no way to go from a file handle back to a file,
599 // since file name information isn't stored with the handle. Tried to think of
600 // a good way to handle this, couldn't come up with anything. For now, it
601 // returns ENOSYS (not implemented).
603 int _fstat (int fd __attribute__ ((unused)), struct stat *st __attribute__ ((unused)))
605 return set_errno (ENOSYS);
608 int _stat (const char *fname, struct stat *st)
613 if ((f = f_stat (fname, &fi)) != FR_OK)
614 return remap_fatfs_errors (f);
616 __builtin_memset (st, 0, sizeof (* st));
618 st->st_mode |= (fi.fattrib & AM_DIR) ? S_IFDIR : S_IFREG;
619 st->st_mode |= (fi.fattrib & AM_RDO) ? ((S_IRWXU & ~S_IWUSR) | (S_IRWXG & ~S_IWGRP) | (S_IRWXO & ~S_IWOTH)) : (S_IRWXU | S_IRWXG | S_IRWXO);
620 st->st_size = fi.fsize;
621 st->st_ctime = fatfs_time_to_timet (&fi);
622 st->st_mtime = st->st_ctime;
623 st->st_atime = st->st_ctime;
624 st->st_blksize = 512;
630 // FatFS and FAT file systems don't support links
634 return set_errno (ENOSYS);
637 int _unlink (const char *path)
641 if ((f = f_unlink (path)) != FR_OK)
642 return remap_fatfs_errors (f);
652 int _gettimeofday (struct timeval *tp, struct timezone *tzp)
654 unsigned int milliseconds;
658 tp->tv_sec = rtcGetEpochSeconds (&milliseconds);
659 tp->tv_usec = milliseconds * 1000;
663 // Return fixed data for the timezone
667 tzp->tz_minuteswest = 0;
675 // Return a clock that ticks at 100Hz
677 clock_t _times (struct tms *tp)
679 clock_t timeval = (clock_t) xTaskGetTickCount ();
683 tp->tms_utime = timeval;
694 return (fd <= 2) ? 1 : 0; /* one of stdin, stdout, stderr */
697 int _system (const char *s)
702 return set_errno (ENOSYS);
705 int _rename (const char *oldpath, const char *newpath)
709 if ((f = f_rename (oldpath, newpath)))
710 return remap_fatfs_errors (f);
716 // Default crossdev -t options for ARM newlib doesn't define HAVE_RENAME, so
717 // it's trying to use the link/unlink process. FatFS doesn't support link(),
718 // so override the newlib rename() to make it work correctly.
720 int rename (const char *oldpath, const char *newpath)
722 return _rename (oldpath, newpath);
729 for (slot = 0; slot < MAX_OPEN_FILES; slot++)
730 if (openfiles [slot].fatfsFCB)
731 f_sync (openfiles [slot].fatfsFCB);