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