1 /* Copyright (c) 2009, 2010, 2011, 2012 ARM Ltd.  All rights reserved.
2 
3  Redistribution and use in source and binary forms, with or without
4  modification, are permitted provided that the following conditions
5  are met:
6  1. Redistributions of source code must retain the above copyright
7     notice, this list of conditions and the following disclaimer.
8  2. Redistributions in binary form must reproduce the above copyright
9     notice, this list of conditions and the following disclaimer in the
10     documentation and/or other materials provided with the distribution.
11  3. The name of the company may not be used to endorse or promote
12     products derived from this software without specific prior written
13     permission.
14 
15  THIS SOFTWARE IS PROVIDED BY ARM LTD ``AS IS'' AND ANY EXPRESS OR IMPLIED
16  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
17  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  IN NO EVENT SHALL ARM LTD BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
20  TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
22  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
23  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
25 
26 /* Support files for GNU libc.  Files in the system namespace go here.
27    Files in the C namespace (ie those that do not start with an
28    underscore) go in .c.  */
29 
30 #include <_ansi.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <sys/fcntl.h>
34 #include <stdio.h>
35 #include <string.h>
36 #include <time.h>
37 #include <sys/time.h>
38 #include <sys/times.h>
39 #include <errno.h>
40 #include <reent.h>
41 #include <unistd.h>
42 #include <sys/wait.h>
43 #include "svc.h"
44 
45 /* Safe casting in both LP64 and ILP32.  */
46 #define POINTER_TO_PARAM_BLOCK_T(PTR)		\
47   (param_block_t)(unsigned long) (PTR)
48 
49 /* Forward prototypes.  */
50 int _system _PARAMS ((const char *));
51 int _rename _PARAMS ((const char *, const char *));
52 int _isatty _PARAMS ((int));
53 clock_t _times _PARAMS ((struct tms *));
54 int _gettimeofday _PARAMS ((struct timeval *, void *));
55 int _unlink _PARAMS ((const char *));
56 int _link _PARAMS ((void));
57 int _stat _PARAMS ((const char *, struct stat *));
58 int _fstat _PARAMS ((int, struct stat *));
59 int _swistat _PARAMS ((int fd, struct stat * st));
60 caddr_t _sbrk _PARAMS ((int));
61 int _getpid _PARAMS ((int));
62 int _close _PARAMS ((int));
63 clock_t _clock _PARAMS ((void));
64 int _swiclose _PARAMS ((int));
65 int _open _PARAMS ((const char *, int, ...));
66 int _swiopen _PARAMS ((const char *, int));
67 int _write _PARAMS ((int, char *, int));
68 int _swiwrite _PARAMS ((int, char *, int));
69 int _lseek _PARAMS ((int, int, int));
70 int _swilseek _PARAMS ((int, int, int));
71 int _read _PARAMS ((int, char *, int));
72 int _swiread _PARAMS ((int, char *, int));
73 void initialise_monitor_handles _PARAMS ((void));
74 
75 static int checkerror _PARAMS ((int));
76 static int error _PARAMS ((int));
77 static int get_errno _PARAMS ((void));
78 
79 /* Struct used to keep track of the file position, just so we
80    can implement fseek(fh,x,SEEK_CUR).  */
81 struct fdent
82 {
83   int handle;
84   int flags;
85   ino_t ino;
86   int pos;
87 };
88 
89 #define MAX_OPEN_FILES 20
90 
91 /* User file descriptors (fd) are integer indexes into
92    the openfiles[] array. Error checking is done by using
93    findslot().
94 
95    This openfiles array is manipulated directly by only
96    these 5 functions:
97 
98 	findslot() - Translate entry.
99 	newslot() - Find empty entry.
100 	initilise_monitor_handles() - Initialize entries.
101 	_swiopen() - Initialize entry.
102 	_close() - Handle stdout == stderr case.
103 
104    Every other function must use findslot().  */
105 
106 static struct fdent openfiles[MAX_OPEN_FILES];
107 
108 static struct fdent *findslot _PARAMS ((int));
109 static int newslot _PARAMS ((void));
110 
111 /* Register name faking - works in collusion with the linker.  */
112 #ifdef __ILP32__
113 register char * stack_ptr asm ("wsp");
114 #else
115 register char * stack_ptr asm ("sp");
116 #endif
117 
118 
119 /* following is copied from libc/stdio/local.h to check std streams */
120 extern void _EXFUN (__sinit, (struct _reent *));
121 #define CHECK_INIT(ptr) \
122   do						\
123     {						\
124       if ((ptr) && !(ptr)->__sdidinit)		\
125 	__sinit (ptr);				\
126     }						\
127   while (0)
128 
129 static int monitor_stdin;
130 static int monitor_stdout;
131 static int monitor_stderr;
132 
133 /* Return a pointer to the structure associated with
134    the user file descriptor fd. */
135 static struct fdent *
findslot(int fd)136 findslot (int fd)
137 {
138   CHECK_INIT (_REENT);
139 
140   /* User file descriptor is out of range. */
141   if ((unsigned int) fd >= MAX_OPEN_FILES)
142     return NULL;
143 
144   /* User file descriptor is open? */
145   if (openfiles[fd].handle == -1)
146     return NULL;
147 
148   /* Valid. */
149   return &openfiles[fd];
150 }
151 
152 /* Return the next lowest numbered free file
153    structure, or -1 if we can't find one. */
154 static int
newslot(void)155 newslot (void)
156 {
157   int i;
158 
159   for (i = 0; i < MAX_OPEN_FILES; i++)
160     if (openfiles[i].handle == -1)
161       break;
162 
163   if (i == MAX_OPEN_FILES)
164     return -1;
165 
166   return i;
167 }
168 
169 void
initialise_monitor_handles(void)170 initialise_monitor_handles (void)
171 {
172   int i;
173 
174   /* Open the standard file descriptors by opening the special
175    * teletype device, ":tt", read-only to obtain a descritpor for
176    * standard input and write-only to obtain a descriptor for standard
177    * output. Finally, open ":tt" in append mode to obtain a descriptor
178    * for standard error. Since this is a write mode, most kernels will
179    * probably return the same value as for standard output, but the
180    * kernel can differentiate the two using the mode flag and return a
181    * different descriptor for standard error.
182    */
183 
184   param_block_t block[3];
185 
186   block[0] = POINTER_TO_PARAM_BLOCK_T (":tt");
187   block[2] = 3;			/* length of filename */
188   block[1] = 0;			/* mode "r" */
189   monitor_stdin = do_AngelSVC (AngelSVC_Reason_Open, block);
190 
191   block[0] = POINTER_TO_PARAM_BLOCK_T (":tt");
192   block[2] = 3;			/* length of filename */
193   block[1] = 4;			/* mode "w" */
194   monitor_stdout = do_AngelSVC (AngelSVC_Reason_Open, block);
195 
196   block[0] = POINTER_TO_PARAM_BLOCK_T (":tt");
197   block[2] = 3;			/* length of filename */
198   block[1] = 8;			/* mode "a" */
199   monitor_stderr = do_AngelSVC (AngelSVC_Reason_Open, block);
200 
201   /* If we failed to open stderr, redirect to stdout. */
202   if (monitor_stderr == -1)
203     monitor_stderr = monitor_stdout;
204 
205   for (i = 0; i < MAX_OPEN_FILES; i++)
206     openfiles[i].handle = -1;
207 
208   openfiles[0].handle = monitor_stdin;
209   openfiles[0].flags = _FREAD;
210   openfiles[0].pos = 0;
211   openfiles[1].handle = monitor_stdout;
212   openfiles[0].flags = _FWRITE;
213   openfiles[1].pos = 0;
214   openfiles[2].handle = monitor_stderr;
215   openfiles[0].flags = _FWRITE;
216   openfiles[2].pos = 0;
217 }
218 
219 static int
get_errno(void)220 get_errno (void)
221 {
222   return do_AngelSVC (AngelSVC_Reason_Errno, NULL);
223 }
224 
225 /* Set errno and return result. */
226 static int
error(int result)227 error (int result)
228 {
229   errno = get_errno ();
230   return result;
231 }
232 
233 /* Check the return and set errno appropriately. */
234 static int
checkerror(int result)235 checkerror (int result)
236 {
237   if (result == -1)
238     return error (-1);
239   return result;
240 }
241 
242 /* fh, is a valid internal file handle.
243    ptr, is a null terminated string.
244    len, is the length in bytes to read.
245    Returns the number of bytes *not* written. */
246 int
_swiread(int fh,char * ptr,int len)247 _swiread (int fh, char *ptr, int len)
248 {
249   param_block_t block[3];
250 
251   block[0] = fh;
252   block[1] = POINTER_TO_PARAM_BLOCK_T (ptr);
253   block[2] = len;
254 
255   return checkerror (do_AngelSVC (AngelSVC_Reason_Read, block));
256 }
257 
258 /* fd, is a valid user file handle.
259    Translates the return of _swiread into
260    bytes read. */
261 int
_read(int fd,char * ptr,int len)262 _read (int fd, char *ptr, int len)
263 {
264   int res;
265   struct fdent *pfd;
266 
267   pfd = findslot (fd);
268   if (pfd == NULL)
269     {
270       errno = EBADF;
271       return -1;
272     }
273 
274   res = _swiread (pfd->handle, ptr, len);
275 
276   if (res == -1)
277     return res;
278 
279   pfd->pos += len - res;
280 
281   /* res == len is not an error,
282      at least if we want feof() to work.  */
283   return len - res;
284 }
285 
286 /* fd, is a user file descriptor. */
287 int
_swilseek(int fd,int ptr,int dir)288 _swilseek (int fd, int ptr, int dir)
289 {
290   int res;
291   struct fdent *pfd;
292 
293   /* Valid file descriptor? */
294   pfd = findslot (fd);
295   if (pfd == NULL)
296     {
297       errno = EBADF;
298       return -1;
299     }
300 
301   /* Valid whence? */
302   if ((dir != SEEK_CUR) && (dir != SEEK_SET) && (dir != SEEK_END))
303     {
304       errno = EINVAL;
305       return -1;
306     }
307 
308   /* Convert SEEK_CUR to SEEK_SET */
309   if (dir == SEEK_CUR)
310     {
311       ptr = pfd->pos + ptr;
312       /* The resulting file offset would be negative. */
313       if (ptr < 0)
314 	{
315 	  errno = EINVAL;
316 	  if ((pfd->pos > 0) && (ptr > 0))
317 	    errno = EOVERFLOW;
318 	  return -1;
319 	}
320       dir = SEEK_SET;
321     }
322 
323   param_block_t block[2];
324   if (dir == SEEK_END)
325     {
326       block[0] = pfd->handle;
327       res = checkerror (do_AngelSVC (AngelSVC_Reason_FLen, block));
328       if (res == -1)
329 	return -1;
330       ptr += res;
331     }
332 
333   /* This code only does absolute seeks.  */
334   block[0] = pfd->handle;
335   block[1] = ptr;
336   res = checkerror (do_AngelSVC (AngelSVC_Reason_Seek, block));
337   /* At this point ptr is the current file position. */
338   if (res >= 0)
339     {
340       pfd->pos = ptr;
341       return ptr;
342     }
343   else
344     return -1;
345 }
346 
_lseek(int fd,int ptr,int dir)347 _lseek (int fd, int ptr, int dir)
348 {
349   return _swilseek (fd, ptr, dir);
350 }
351 
352 /* fh, is a valid internal file handle.
353    Returns the number of bytes *not* written. */
354 int
_swiwrite(int fh,char * ptr,int len)355 _swiwrite (int fh, char *ptr, int len)
356 {
357   param_block_t block[3];
358 
359   block[0] = fh;
360   block[1] = POINTER_TO_PARAM_BLOCK_T (ptr);
361   block[2] = len;
362 
363   return checkerror (do_AngelSVC (AngelSVC_Reason_Write, block));
364 }
365 
366 /* fd, is a user file descriptor. */
367 int
_write(int fd,char * ptr,int len)368 _write (int fd, char *ptr, int len)
369 {
370   int res;
371   struct fdent *pfd;
372 
373   pfd = findslot (fd);
374   if (pfd == NULL)
375     {
376       errno = EBADF;
377       return -1;
378     }
379 
380   res = _swiwrite (pfd->handle, ptr, len);
381 
382   /* Clearly an error. */
383   if (res < 0)
384     return -1;
385 
386   pfd->pos += len - res;
387 
388   /* We wrote 0 bytes?
389      Retrieve errno just in case. */
390   if ((len - res) == 0)
391     return error (0);
392 
393   return (len - res);
394 }
395 
396 int
_swiopen(const char * path,int flags)397 _swiopen (const char *path, int flags)
398 {
399   int aflags = 0, fh;
400   param_block_t block[3];
401   static ino_t ino = 1;
402   int fd;
403 
404   if (path == NULL)
405     {
406       errno = ENOENT;
407       return -1;
408     }
409 
410   fd = newslot ();
411 
412   if (fd == -1)
413     {
414       errno = EMFILE;
415       return -1;
416     }
417 
418   /* It is an error to open a file that already exists. */
419   if ((flags & O_CREAT) && (flags & O_EXCL))
420     {
421       struct stat st;
422       int res;
423       res = _stat (path, &st);
424       if (res != -1)
425 	{
426 	  errno = EEXIST;
427 	  return -1;
428 	}
429     }
430 
431   /* The flags are Unix-style, so we need to convert them. */
432 #ifdef O_BINARY
433   if (flags & O_BINARY)
434     aflags |= 1;
435 #endif
436 
437   /* In O_RDONLY we expect aflags == 0. */
438 
439   if (flags & O_RDWR)
440     aflags |= 2;
441 
442   if ((flags & O_CREAT) || (flags & O_TRUNC) || (flags & O_WRONLY))
443     aflags |= 4;
444 
445   if (flags & O_APPEND)
446     {
447       /* Can't ask for w AND a; means just 'a'.  */
448       aflags &= ~4;
449       aflags |= 8;
450     }
451 
452   block[0] = POINTER_TO_PARAM_BLOCK_T (path);
453   block[2] = strlen (path);
454   block[1] = aflags;
455 
456   fh = do_AngelSVC (AngelSVC_Reason_Open, block);
457 
458   /* Return a user file descriptor or an error. */
459   if (fh >= 0)
460     {
461       openfiles[fd].handle = fh;
462       openfiles[fd].flags = flags + 1;
463       openfiles[fd].ino = ino++;
464       openfiles[fd].pos = 0;
465       return fd;
466     }
467   else
468     return error (fh);
469 }
470 
471 int
_open(const char * path,int flags,...)472 _open (const char *path, int flags, ...)
473 {
474   return _swiopen (path, flags);
475 }
476 
477 /* fh, is a valid internal file handle. */
478 int
_swiclose(int fh)479 _swiclose (int fh)
480 {
481   param_block_t param[1];
482   param[0] = fh;
483   return checkerror (do_AngelSVC (AngelSVC_Reason_Close, param));
484 }
485 
486 /* fd, is a user file descriptor. */
487 int
_close(int fd)488 _close (int fd)
489 {
490   int res;
491   struct fdent *pfd;
492 
493   pfd = findslot (fd);
494   if (pfd == NULL)
495     {
496       errno = EBADF;
497       return -1;
498     }
499 
500   /* Handle stderr == stdout. */
501   if ((fd == 1 || fd == 2) && (openfiles[1].handle == openfiles[2].handle))
502     {
503       pfd->handle = -1;
504       return 0;
505     }
506 
507   /* Attempt to close the handle. */
508   res = _swiclose (pfd->handle);
509 
510   /* Reclaim handle? */
511   if (res == 0)
512     pfd->handle = -1;
513 
514   return res;
515 }
516 
517 int __attribute__((weak))
_getpid(int n)518 _getpid (int n __attribute__ ((unused)))
519 {
520   return 1;
521 }
522 
523 caddr_t
_sbrk(int incr)524 _sbrk (int incr)
525 {
526   extern char end asm ("end");	/* Defined by the linker.  */
527   static char *heap_end;
528   char *prev_heap_end;
529 
530   if (heap_end == NULL)
531     heap_end = &end;
532 
533   prev_heap_end = heap_end;
534 
535   if (heap_end + incr > stack_ptr)
536     {
537       /* Some of the libstdc++-v3 tests rely upon detecting
538          out of memory errors, so do not abort here.  */
539       errno = ENOMEM;
540       return (caddr_t) - 1;
541     }
542 
543   heap_end += incr;
544 
545   return (caddr_t) prev_heap_end;
546 }
547 
548 int
_swistat(int fd,struct stat * st)549 _swistat (int fd, struct stat *st)
550 {
551   struct fdent *pfd;
552   param_block_t param[1];
553   int res;
554 
555   pfd = findslot (fd);
556   if (pfd == NULL)
557     {
558       errno = EBADF;
559       return -1;
560     }
561 
562   param[0] = pfd->handle;
563   res = do_AngelSVC (AngelSVC_Reason_IsTTY, param);
564   if (res != 0 && res != 1)
565     return error (-1);
566 
567   memset (st, 0, sizeof (*st));
568 
569   if (res)
570     {
571       /* This is a tty. */
572       st->st_mode |= S_IFCHR;
573     }
574   else
575     {
576       /* This is a file, return the file length.  */
577       st->st_mode |= S_IFREG;
578       res = checkerror (do_AngelSVC (AngelSVC_Reason_FLen, param));
579       if (res == -1)
580 	return -1;
581       st->st_size = res;
582       st->st_blksize = 1024;
583       st->st_blocks = (res + 1023) / 1024;
584     }
585 
586   /* Deduce permissions based on mode in which file opened.  */
587   st->st_mode |= S_IRUSR | S_IRGRP | S_IROTH;
588   if (pfd->flags & _FWRITE)
589     st->st_mode |= S_IWUSR | S_IWGRP | S_IWOTH;
590 
591   st->st_ino = pfd->ino;
592   st->st_nlink = 1;
593   return 0;
594 }
595 
596 int __attribute__((weak))
_fstat(int fd,struct stat * st)597 _fstat (int fd, struct stat * st)
598 {
599   return _swistat (fd, st);
600 }
601 
602 int __attribute__((weak))
_stat(const char * fname,struct stat * st)603 _stat (const char *fname, struct stat *st)
604 {
605   int fd, res;
606   /* The best we can do is try to open the file readonly.
607      If it exists, then we can guess a few things about it. */
608   if ((fd = _open (fname, O_RDONLY)) == -1)
609     return -1;
610   res = _swistat (fd, st);
611   /* Not interested in the error. */
612   _close (fd);
613   return res;
614 }
615 
616 int __attribute__((weak))
_link(void)617 _link (void)
618 {
619   errno = ENOSYS;
620   return -1;
621 }
622 
623 int
_unlink(const char * path)624 _unlink (const char *path)
625 {
626   int res;
627   param_block_t block[2];
628   block[0] = POINTER_TO_PARAM_BLOCK_T (path);
629   block[1] = strlen (path);
630   res = do_AngelSVC (AngelSVC_Reason_Remove, block);
631   if (res == -1)
632     return error (res);
633   return 0;
634 }
635 
636 int
_gettimeofday(struct timeval * tp,void * tzvp)637 _gettimeofday (struct timeval *tp, void *tzvp)
638 {
639   struct timezone *tzp = tzvp;
640   if (tp)
641     {
642       /* Ask the host for the seconds since the Unix epoch.  */
643       tp->tv_sec = do_AngelSVC (AngelSVC_Reason_Time, NULL);
644       tp->tv_usec = 0;
645     }
646 
647   /* Return fixed data for the timezone.  */
648   if (tzp)
649     {
650       tzp->tz_minuteswest = 0;
651       tzp->tz_dsttime = 0;
652     }
653 
654   return 0;
655 }
656 
657 /* Return a clock that ticks at 100Hz.  */
658 clock_t
_clock(void)659 _clock (void)
660 {
661   clock_t timeval;
662 
663   timeval = do_AngelSVC (AngelSVC_Reason_Clock, NULL);
664   return timeval;
665 }
666 
667 /* Return a clock that ticks at 100Hz.  */
668 clock_t
_times(struct tms * tp)669 _times (struct tms * tp)
670 {
671   clock_t timeval = _clock ();
672 
673   if (tp)
674     {
675       tp->tms_utime = timeval;	/* user time */
676       tp->tms_stime = 0;	/* system time */
677       tp->tms_cutime = 0;	/* user time, children */
678       tp->tms_cstime = 0;	/* system time, children */
679     }
680 
681   return timeval;
682 };
683 
684 
685 int
_isatty(int fd)686 _isatty (int fd)
687 {
688   struct fdent *pfd;
689   param_block_t param[1];
690   int res;
691 
692   /* Return 1 if fd is an open file descriptor referring to a terminal;
693      otherwise 0 is returned, and errno is set to indicate the error.  */
694 
695   pfd = findslot (fd);
696   if (pfd == NULL)
697     {
698       errno = EBADF;
699       return 0;
700     }
701 
702   param[0] = pfd->handle;
703   res = do_AngelSVC (AngelSVC_Reason_IsTTY, param);
704 
705   if (res != 1)
706     return error (0);
707   return res;
708 }
709 
710 int
_system(const char * s)711 _system (const char *s)
712 {
713   param_block_t block[2];
714   int e;
715 
716   /* Hmmm.  The ARM debug interface specification doesn't say whether
717      SYS_SYSTEM does the right thing with a null argument, or assign any
718      meaning to its return value.  Try to do something reasonable....  */
719   if (!s)
720     return 1;			/* maybe there is a shell available? we can hope. :-P */
721   block[0] = POINTER_TO_PARAM_BLOCK_T (s);
722   block[1] = strlen (s);
723   e = checkerror (do_AngelSVC (AngelSVC_Reason_System, block));
724   if ((e >= 0) && (e < 256))
725     {
726       /* We have to convert e, an exit status to the encoded status of
727          the command.  To avoid hard coding the exit status, we simply
728          loop until we find the right position.  */
729       int exit_code;
730 
731       for (exit_code = e; e && WEXITSTATUS (e) != exit_code; e <<= 1)
732 	continue;
733     }
734   return e;
735 }
736 
737 int
_rename(const char * oldpath,const char * newpath)738 _rename (const char *oldpath, const char *newpath)
739 {
740   param_block_t block[4];
741   block[0] = POINTER_TO_PARAM_BLOCK_T (oldpath);
742   block[1] = strlen (oldpath);
743   block[2] = POINTER_TO_PARAM_BLOCK_T (newpath);
744   block[3] = strlen (newpath);
745   return checkerror (do_AngelSVC (AngelSVC_Reason_Rename, block)) ? -1 : 0;
746 }
747 
748 /* Returns the number of elapsed target ticks since the support code
749    started execution. Returns -1 and sets errno on error.  */
750 long
__aarch64_angel_elapsed(void)751 __aarch64_angel_elapsed (void)
752 {
753   int result;
754   param_block_t block[2];
755   result = checkerror (do_AngelSVC (AngelSVC_Reason_Elapsed, block));
756   if (result == -1)
757     return result;
758   return block[0];
759 }
760