| [444] | 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 (const char *); | 
|---|
|  | 51 | int _rename (const char *, const char *); | 
|---|
|  | 52 | int _isatty (int); | 
|---|
|  | 53 | clock_t _times (struct tms *); | 
|---|
|  | 54 | int _gettimeofday (struct timeval *, void *); | 
|---|
|  | 55 | int _unlink (const char *); | 
|---|
|  | 56 | int _link (void); | 
|---|
|  | 57 | int _stat (const char *, struct stat *); | 
|---|
|  | 58 | int _fstat (int, struct stat *); | 
|---|
|  | 59 | int _swistat (int fd, struct stat * st); | 
|---|
|  | 60 | caddr_t _sbrk (int); | 
|---|
|  | 61 | int _getpid (int); | 
|---|
|  | 62 | int _close (int); | 
|---|
|  | 63 | clock_t _clock (void); | 
|---|
|  | 64 | int _swiclose (int); | 
|---|
|  | 65 | int _open (const char *, int, ...); | 
|---|
|  | 66 | int _swiopen (const char *, int); | 
|---|
|  | 67 | int _write (int, char *, int); | 
|---|
|  | 68 | int _swiwrite (int, char *, int); | 
|---|
|  | 69 | int _lseek (int, int, int); | 
|---|
|  | 70 | int _swilseek (int, int, int); | 
|---|
|  | 71 | int _read (int, char *, int); | 
|---|
|  | 72 | int _swiread (int, char *, int); | 
|---|
|  | 73 | void initialise_monitor_handles (void); | 
|---|
|  | 74 |  | 
|---|
|  | 75 | static int checkerror (int); | 
|---|
|  | 76 | static int error (int); | 
|---|
|  | 77 | static int get_errno (void); | 
|---|
|  | 78 |  | 
|---|
|  | 79 | /* Semihosting utilities.  */ | 
|---|
|  | 80 | static void initialise_semihosting_exts (void); | 
|---|
|  | 81 |  | 
|---|
|  | 82 | /* Struct used to keep track of the file position, just so we | 
|---|
|  | 83 | can implement fseek(fh,x,SEEK_CUR).  */ | 
|---|
|  | 84 | struct fdent | 
|---|
|  | 85 | { | 
|---|
|  | 86 | int handle; | 
|---|
|  | 87 | int flags; | 
|---|
|  | 88 | ino_t ino; | 
|---|
|  | 89 | int pos; | 
|---|
|  | 90 | }; | 
|---|
|  | 91 |  | 
|---|
|  | 92 | #define MAX_OPEN_FILES 20 | 
|---|
|  | 93 |  | 
|---|
|  | 94 | /* User file descriptors (fd) are integer indexes into | 
|---|
|  | 95 | the openfiles[] array. Error checking is done by using | 
|---|
|  | 96 | findslot(). | 
|---|
|  | 97 |  | 
|---|
|  | 98 | This openfiles array is manipulated directly by only | 
|---|
|  | 99 | these 5 functions: | 
|---|
|  | 100 |  | 
|---|
|  | 101 | findslot() - Translate entry. | 
|---|
|  | 102 | newslot() - Find empty entry. | 
|---|
|  | 103 | initilise_monitor_handles() - Initialize entries. | 
|---|
|  | 104 | _swiopen() - Initialize entry. | 
|---|
|  | 105 | _close() - Handle stdout == stderr case. | 
|---|
|  | 106 |  | 
|---|
|  | 107 | Every other function must use findslot().  */ | 
|---|
|  | 108 |  | 
|---|
|  | 109 | static struct fdent openfiles[MAX_OPEN_FILES]; | 
|---|
|  | 110 |  | 
|---|
|  | 111 | static struct fdent *findslot (int); | 
|---|
|  | 112 | static int newslot (void); | 
|---|
|  | 113 |  | 
|---|
|  | 114 | /* Register name faking - works in collusion with the linker.  */ | 
|---|
|  | 115 | #ifdef __ILP32__ | 
|---|
|  | 116 | register char * stack_ptr asm ("wsp"); | 
|---|
|  | 117 | #else | 
|---|
|  | 118 | register char * stack_ptr asm ("sp"); | 
|---|
|  | 119 | #endif | 
|---|
|  | 120 |  | 
|---|
|  | 121 |  | 
|---|
|  | 122 | /* following is copied from libc/stdio/local.h to check std streams */ | 
|---|
|  | 123 | extern void __sinit (struct _reent *); | 
|---|
|  | 124 | #define CHECK_INIT(ptr) \ | 
|---|
|  | 125 | do                                            \ | 
|---|
|  | 126 | {                                           \ | 
|---|
|  | 127 | if ((ptr) && !(ptr)->__sdidinit)          \ | 
|---|
|  | 128 | __sinit (ptr);                          \ | 
|---|
|  | 129 | }                                           \ | 
|---|
|  | 130 | while (0) | 
|---|
|  | 131 |  | 
|---|
|  | 132 | static int monitor_stdin; | 
|---|
|  | 133 | static int monitor_stdout; | 
|---|
|  | 134 | static int monitor_stderr; | 
|---|
|  | 135 |  | 
|---|
|  | 136 | static int supports_ext_exit_extended = -1; | 
|---|
|  | 137 | static int supports_ext_stdout_stderr = -1; | 
|---|
|  | 138 |  | 
|---|
|  | 139 | /* Return a pointer to the structure associated with | 
|---|
|  | 140 | the user file descriptor fd. */ | 
|---|
|  | 141 | static struct fdent * | 
|---|
|  | 142 | findslot (int fd) | 
|---|
|  | 143 | { | 
|---|
|  | 144 | CHECK_INIT (_REENT); | 
|---|
|  | 145 |  | 
|---|
|  | 146 | /* User file descriptor is out of range. */ | 
|---|
|  | 147 | if ((unsigned int) fd >= MAX_OPEN_FILES) | 
|---|
|  | 148 | return NULL; | 
|---|
|  | 149 |  | 
|---|
|  | 150 | /* User file descriptor is open? */ | 
|---|
|  | 151 | if (openfiles[fd].handle == -1) | 
|---|
|  | 152 | return NULL; | 
|---|
|  | 153 |  | 
|---|
|  | 154 | /* Valid. */ | 
|---|
|  | 155 | return &openfiles[fd]; | 
|---|
|  | 156 | } | 
|---|
|  | 157 |  | 
|---|
|  | 158 | /* Return the next lowest numbered free file | 
|---|
|  | 159 | structure, or -1 if we can't find one. */ | 
|---|
|  | 160 | static int | 
|---|
|  | 161 | newslot (void) | 
|---|
|  | 162 | { | 
|---|
|  | 163 | int i; | 
|---|
|  | 164 |  | 
|---|
|  | 165 | for (i = 0; i < MAX_OPEN_FILES; i++) | 
|---|
|  | 166 | if (openfiles[i].handle == -1) | 
|---|
|  | 167 | break; | 
|---|
|  | 168 |  | 
|---|
|  | 169 | if (i == MAX_OPEN_FILES) | 
|---|
|  | 170 | return -1; | 
|---|
|  | 171 |  | 
|---|
|  | 172 | return i; | 
|---|
|  | 173 | } | 
|---|
|  | 174 |  | 
|---|
|  | 175 | void | 
|---|
|  | 176 | initialise_monitor_handles (void) | 
|---|
|  | 177 | { | 
|---|
|  | 178 | int i; | 
|---|
|  | 179 |  | 
|---|
|  | 180 | /* Open the standard file descriptors by opening the special | 
|---|
|  | 181 | * teletype device, ":tt", read-only to obtain a descritpor for | 
|---|
|  | 182 | * standard input and write-only to obtain a descriptor for standard | 
|---|
|  | 183 | * output. Finally, open ":tt" in append mode to obtain a descriptor | 
|---|
|  | 184 | * for standard error. Since this is a write mode, most kernels will | 
|---|
|  | 185 | * probably return the same value as for standard output, but the | 
|---|
|  | 186 | * kernel can differentiate the two using the mode flag and return a | 
|---|
|  | 187 | * different descriptor for standard error. | 
|---|
|  | 188 | */ | 
|---|
|  | 189 |  | 
|---|
|  | 190 | param_block_t block[3]; | 
|---|
|  | 191 |  | 
|---|
|  | 192 | block[0] = POINTER_TO_PARAM_BLOCK_T (":tt"); | 
|---|
|  | 193 | block[2] = 3;                 /* length of filename */ | 
|---|
|  | 194 | block[1] = 0;                 /* mode "r" */ | 
|---|
|  | 195 | monitor_stdin = do_AngelSVC (AngelSVC_Reason_Open, block); | 
|---|
|  | 196 |  | 
|---|
|  | 197 | for (i = 0; i < MAX_OPEN_FILES; i++) | 
|---|
|  | 198 | openfiles[i].handle = -1;; | 
|---|
|  | 199 |  | 
|---|
|  | 200 | if (_has_ext_stdout_stderr ()) | 
|---|
|  | 201 | { | 
|---|
|  | 202 | block[0] = POINTER_TO_PARAM_BLOCK_T (":tt"); | 
|---|
|  | 203 | block[2] = 3;                       /* length of filename */ | 
|---|
|  | 204 | block[1] = 4;                       /* mode "w" */ | 
|---|
|  | 205 | monitor_stdout = do_AngelSVC (AngelSVC_Reason_Open, block); | 
|---|
|  | 206 |  | 
|---|
|  | 207 | block[0] = POINTER_TO_PARAM_BLOCK_T (":tt"); | 
|---|
|  | 208 | block[2] = 3;                       /* length of filename */ | 
|---|
|  | 209 | block[1] = 8;                       /* mode "a" */ | 
|---|
|  | 210 | monitor_stderr = do_AngelSVC (AngelSVC_Reason_Open, block); | 
|---|
|  | 211 | } | 
|---|
|  | 212 |  | 
|---|
|  | 213 | /* If we failed to open stderr, redirect to stdout. */ | 
|---|
|  | 214 | if (monitor_stderr == -1) | 
|---|
|  | 215 | monitor_stderr = monitor_stdout; | 
|---|
|  | 216 |  | 
|---|
|  | 217 | openfiles[0].handle = monitor_stdin; | 
|---|
|  | 218 | openfiles[0].flags = _FREAD; | 
|---|
|  | 219 | openfiles[0].pos = 0; | 
|---|
|  | 220 |  | 
|---|
|  | 221 | if (_has_ext_stdout_stderr ()) | 
|---|
|  | 222 | { | 
|---|
|  | 223 | openfiles[1].handle = monitor_stdout; | 
|---|
|  | 224 | openfiles[0].flags = _FWRITE; | 
|---|
|  | 225 | openfiles[1].pos = 0; | 
|---|
|  | 226 | openfiles[2].handle = monitor_stderr; | 
|---|
|  | 227 | openfiles[0].flags = _FWRITE; | 
|---|
|  | 228 | openfiles[2].pos = 0; | 
|---|
|  | 229 | } | 
|---|
|  | 230 | } | 
|---|
|  | 231 |  | 
|---|
|  | 232 | int | 
|---|
|  | 233 | _has_ext_exit_extended (void) | 
|---|
|  | 234 | { | 
|---|
|  | 235 | if (supports_ext_exit_extended < 0) | 
|---|
|  | 236 | { | 
|---|
|  | 237 | initialise_semihosting_exts (); | 
|---|
|  | 238 | } | 
|---|
|  | 239 |  | 
|---|
|  | 240 | return supports_ext_exit_extended; | 
|---|
|  | 241 | } | 
|---|
|  | 242 |  | 
|---|
|  | 243 | int | 
|---|
|  | 244 | _has_ext_stdout_stderr (void) | 
|---|
|  | 245 | { | 
|---|
|  | 246 | if (supports_ext_stdout_stderr < 0) | 
|---|
|  | 247 | { | 
|---|
|  | 248 | initialise_semihosting_exts (); | 
|---|
|  | 249 | } | 
|---|
|  | 250 |  | 
|---|
|  | 251 | return supports_ext_stdout_stderr; | 
|---|
|  | 252 | } | 
|---|
|  | 253 |  | 
|---|
|  | 254 | static void | 
|---|
|  | 255 | initialise_semihosting_exts (void) | 
|---|
|  | 256 | { | 
|---|
|  | 257 | supports_ext_exit_extended = 0; | 
|---|
|  | 258 | supports_ext_stdout_stderr = 1; | 
|---|
|  | 259 |  | 
|---|
|  | 260 | #if SEMIHOST_V2 | 
|---|
|  | 261 | char features[1]; | 
|---|
|  | 262 | if (_get_semihosting_exts (features, 0, 1) > 0) | 
|---|
|  | 263 | { | 
|---|
|  | 264 | supports_ext_exit_extended | 
|---|
|  | 265 | = features[0] & (1 << SH_EXT_EXIT_EXTENDED_BITNUM); | 
|---|
|  | 266 | supports_ext_stdout_stderr | 
|---|
|  | 267 | = features[0] & (1 << SH_EXT_STDOUT_STDERR_BITNUM); | 
|---|
|  | 268 | } | 
|---|
|  | 269 | #endif | 
|---|
|  | 270 | } | 
|---|
|  | 271 |  | 
|---|
|  | 272 | int | 
|---|
|  | 273 | _get_semihosting_exts (char* features, int offset, int num) | 
|---|
|  | 274 | { | 
|---|
|  | 275 | int fd = _open (":semihosting-features", O_RDONLY); | 
|---|
|  | 276 | memset (features, 0, num); | 
|---|
|  | 277 |  | 
|---|
|  | 278 | if (fd == -1) | 
|---|
|  | 279 | { | 
|---|
|  | 280 | return -1; | 
|---|
|  | 281 | } | 
|---|
|  | 282 |  | 
|---|
|  | 283 | struct fdent *pfd; | 
|---|
|  | 284 | pfd = findslot (fd); | 
|---|
|  | 285 |  | 
|---|
|  | 286 | param_block_t block[1]; | 
|---|
|  | 287 | block[0] = pfd->handle; | 
|---|
|  | 288 |  | 
|---|
|  | 289 | int len = do_AngelSVC (AngelSVC_Reason_FLen, block); | 
|---|
|  | 290 |  | 
|---|
|  | 291 | if (len < NUM_SHFB_MAGIC | 
|---|
|  | 292 | || num > (len - NUM_SHFB_MAGIC)) | 
|---|
|  | 293 | { | 
|---|
|  | 294 | _close (fd); | 
|---|
|  | 295 | return -1; | 
|---|
|  | 296 | } | 
|---|
|  | 297 |  | 
|---|
|  | 298 | char buffer[NUM_SHFB_MAGIC]; | 
|---|
|  | 299 | int n_read = _read (fd, buffer, NUM_SHFB_MAGIC); | 
|---|
|  | 300 |  | 
|---|
|  | 301 | if (n_read < NUM_SHFB_MAGIC | 
|---|
|  | 302 | || buffer[0] != SHFB_MAGIC_0 | 
|---|
|  | 303 | || buffer[1] != SHFB_MAGIC_1 | 
|---|
|  | 304 | || buffer[2] != SHFB_MAGIC_2 | 
|---|
|  | 305 | || buffer[3] != SHFB_MAGIC_3) | 
|---|
|  | 306 | { | 
|---|
|  | 307 | _close (fd); | 
|---|
|  | 308 | return -1; | 
|---|
|  | 309 | } | 
|---|
|  | 310 |  | 
|---|
|  | 311 | if (_lseek (fd, offset, SEEK_CUR) < 0) | 
|---|
|  | 312 | { | 
|---|
|  | 313 | _close (fd); | 
|---|
|  | 314 | return -1; | 
|---|
|  | 315 | } | 
|---|
|  | 316 |  | 
|---|
|  | 317 | n_read = _read (fd, features, num); | 
|---|
|  | 318 |  | 
|---|
|  | 319 | _close (fd); | 
|---|
|  | 320 |  | 
|---|
|  | 321 | return checkerror (n_read); | 
|---|
|  | 322 | } | 
|---|
|  | 323 |  | 
|---|
|  | 324 | static int | 
|---|
|  | 325 | get_errno (void) | 
|---|
|  | 326 | { | 
|---|
|  | 327 | return do_AngelSVC (AngelSVC_Reason_Errno, NULL); | 
|---|
|  | 328 | } | 
|---|
|  | 329 |  | 
|---|
|  | 330 | /* Set errno and return result. */ | 
|---|
|  | 331 | static int | 
|---|
|  | 332 | error (int result) | 
|---|
|  | 333 | { | 
|---|
|  | 334 | errno = get_errno (); | 
|---|
|  | 335 | return result; | 
|---|
|  | 336 | } | 
|---|
|  | 337 |  | 
|---|
|  | 338 | /* Check the return and set errno appropriately. */ | 
|---|
|  | 339 | static int | 
|---|
|  | 340 | checkerror (int result) | 
|---|
|  | 341 | { | 
|---|
|  | 342 | if (result == -1) | 
|---|
|  | 343 | return error (-1); | 
|---|
|  | 344 | return result; | 
|---|
|  | 345 | } | 
|---|
|  | 346 |  | 
|---|
|  | 347 | /* fh, is a valid internal file handle. | 
|---|
|  | 348 | ptr, is a null terminated string. | 
|---|
|  | 349 | len, is the length in bytes to read. | 
|---|
|  | 350 | Returns the number of bytes *not* written. */ | 
|---|
|  | 351 | int | 
|---|
|  | 352 | _swiread (int fh, char *ptr, int len) | 
|---|
|  | 353 | { | 
|---|
|  | 354 | param_block_t block[3]; | 
|---|
|  | 355 |  | 
|---|
|  | 356 | block[0] = fh; | 
|---|
|  | 357 | block[1] = POINTER_TO_PARAM_BLOCK_T (ptr); | 
|---|
|  | 358 | block[2] = len; | 
|---|
|  | 359 |  | 
|---|
|  | 360 | return checkerror (do_AngelSVC (AngelSVC_Reason_Read, block)); | 
|---|
|  | 361 | } | 
|---|
|  | 362 |  | 
|---|
|  | 363 | /* fd, is a valid user file handle. | 
|---|
|  | 364 | Translates the return of _swiread into | 
|---|
|  | 365 | bytes read. */ | 
|---|
|  | 366 | int | 
|---|
|  | 367 | _read (int fd, char *ptr, int len) | 
|---|
|  | 368 | { | 
|---|
|  | 369 | int res; | 
|---|
|  | 370 | struct fdent *pfd; | 
|---|
|  | 371 |  | 
|---|
|  | 372 | pfd = findslot (fd); | 
|---|
|  | 373 | if (pfd == NULL) | 
|---|
|  | 374 | { | 
|---|
|  | 375 | errno = EBADF; | 
|---|
|  | 376 | return -1; | 
|---|
|  | 377 | } | 
|---|
|  | 378 |  | 
|---|
|  | 379 | res = _swiread (pfd->handle, ptr, len); | 
|---|
|  | 380 |  | 
|---|
|  | 381 | if (res == -1) | 
|---|
|  | 382 | return res; | 
|---|
|  | 383 |  | 
|---|
|  | 384 | pfd->pos += len - res; | 
|---|
|  | 385 |  | 
|---|
|  | 386 | /* res == len is not an error, | 
|---|
|  | 387 | at least if we want feof() to work.  */ | 
|---|
|  | 388 | return len - res; | 
|---|
|  | 389 | } | 
|---|
|  | 390 |  | 
|---|
|  | 391 | /* fd, is a user file descriptor. */ | 
|---|
|  | 392 | int | 
|---|
|  | 393 | _swilseek (int fd, int ptr, int dir) | 
|---|
|  | 394 | { | 
|---|
|  | 395 | int res; | 
|---|
|  | 396 | struct fdent *pfd; | 
|---|
|  | 397 |  | 
|---|
|  | 398 | /* Valid file descriptor? */ | 
|---|
|  | 399 | pfd = findslot (fd); | 
|---|
|  | 400 | if (pfd == NULL) | 
|---|
|  | 401 | { | 
|---|
|  | 402 | errno = EBADF; | 
|---|
|  | 403 | return -1; | 
|---|
|  | 404 | } | 
|---|
|  | 405 |  | 
|---|
|  | 406 | /* Valid whence? */ | 
|---|
|  | 407 | if ((dir != SEEK_CUR) && (dir != SEEK_SET) && (dir != SEEK_END)) | 
|---|
|  | 408 | { | 
|---|
|  | 409 | errno = EINVAL; | 
|---|
|  | 410 | return -1; | 
|---|
|  | 411 | } | 
|---|
|  | 412 |  | 
|---|
|  | 413 | /* Convert SEEK_CUR to SEEK_SET */ | 
|---|
|  | 414 | if (dir == SEEK_CUR) | 
|---|
|  | 415 | { | 
|---|
|  | 416 | ptr = pfd->pos + ptr; | 
|---|
|  | 417 | /* The resulting file offset would be negative. */ | 
|---|
|  | 418 | if (ptr < 0) | 
|---|
|  | 419 | { | 
|---|
|  | 420 | errno = EINVAL; | 
|---|
|  | 421 | if ((pfd->pos > 0) && (ptr > 0)) | 
|---|
|  | 422 | errno = EOVERFLOW; | 
|---|
|  | 423 | return -1; | 
|---|
|  | 424 | } | 
|---|
|  | 425 | dir = SEEK_SET; | 
|---|
|  | 426 | } | 
|---|
|  | 427 |  | 
|---|
|  | 428 | param_block_t block[2]; | 
|---|
|  | 429 | if (dir == SEEK_END) | 
|---|
|  | 430 | { | 
|---|
|  | 431 | block[0] = pfd->handle; | 
|---|
|  | 432 | res = checkerror (do_AngelSVC (AngelSVC_Reason_FLen, block)); | 
|---|
|  | 433 | if (res == -1) | 
|---|
|  | 434 | return -1; | 
|---|
|  | 435 | ptr += res; | 
|---|
|  | 436 | } | 
|---|
|  | 437 |  | 
|---|
|  | 438 | /* This code only does absolute seeks.  */ | 
|---|
|  | 439 | block[0] = pfd->handle; | 
|---|
|  | 440 | block[1] = ptr; | 
|---|
|  | 441 | res = checkerror (do_AngelSVC (AngelSVC_Reason_Seek, block)); | 
|---|
|  | 442 | /* At this point ptr is the current file position. */ | 
|---|
|  | 443 | if (res >= 0) | 
|---|
|  | 444 | { | 
|---|
|  | 445 | pfd->pos = ptr; | 
|---|
|  | 446 | return ptr; | 
|---|
|  | 447 | } | 
|---|
|  | 448 | else | 
|---|
|  | 449 | return -1; | 
|---|
|  | 450 | } | 
|---|
|  | 451 |  | 
|---|
|  | 452 | _lseek (int fd, int ptr, int dir) | 
|---|
|  | 453 | { | 
|---|
|  | 454 | return _swilseek (fd, ptr, dir); | 
|---|
|  | 455 | } | 
|---|
|  | 456 |  | 
|---|
|  | 457 | /* fh, is a valid internal file handle. | 
|---|
|  | 458 | Returns the number of bytes *not* written. */ | 
|---|
|  | 459 | int | 
|---|
|  | 460 | _swiwrite (int fh, char *ptr, int len) | 
|---|
|  | 461 | { | 
|---|
|  | 462 | param_block_t block[3]; | 
|---|
|  | 463 |  | 
|---|
|  | 464 | block[0] = fh; | 
|---|
|  | 465 | block[1] = POINTER_TO_PARAM_BLOCK_T (ptr); | 
|---|
|  | 466 | block[2] = len; | 
|---|
|  | 467 |  | 
|---|
|  | 468 | return checkerror (do_AngelSVC (AngelSVC_Reason_Write, block)); | 
|---|
|  | 469 | } | 
|---|
|  | 470 |  | 
|---|
|  | 471 | /* fd, is a user file descriptor. */ | 
|---|
|  | 472 | int | 
|---|
|  | 473 | _write (int fd, char *ptr, int len) | 
|---|
|  | 474 | { | 
|---|
|  | 475 | int res; | 
|---|
|  | 476 | struct fdent *pfd; | 
|---|
|  | 477 |  | 
|---|
|  | 478 | pfd = findslot (fd); | 
|---|
|  | 479 | if (pfd == NULL) | 
|---|
|  | 480 | { | 
|---|
|  | 481 | errno = EBADF; | 
|---|
|  | 482 | return -1; | 
|---|
|  | 483 | } | 
|---|
|  | 484 |  | 
|---|
|  | 485 | res = _swiwrite (pfd->handle, ptr, len); | 
|---|
|  | 486 |  | 
|---|
|  | 487 | /* Clearly an error. */ | 
|---|
|  | 488 | if (res < 0) | 
|---|
|  | 489 | return -1; | 
|---|
|  | 490 |  | 
|---|
|  | 491 | pfd->pos += len - res; | 
|---|
|  | 492 |  | 
|---|
|  | 493 | /* We wrote 0 bytes? | 
|---|
|  | 494 | Retrieve errno just in case. */ | 
|---|
|  | 495 | if ((len - res) == 0) | 
|---|
|  | 496 | return error (0); | 
|---|
|  | 497 |  | 
|---|
|  | 498 | return (len - res); | 
|---|
|  | 499 | } | 
|---|
|  | 500 |  | 
|---|
|  | 501 | int | 
|---|
|  | 502 | _swiopen (const char *path, int flags) | 
|---|
|  | 503 | { | 
|---|
|  | 504 | int aflags = 0, fh; | 
|---|
|  | 505 | param_block_t block[3]; | 
|---|
|  | 506 | static ino_t ino = 1; | 
|---|
|  | 507 | int fd; | 
|---|
|  | 508 |  | 
|---|
|  | 509 | if (path == NULL) | 
|---|
|  | 510 | { | 
|---|
|  | 511 | errno = ENOENT; | 
|---|
|  | 512 | return -1; | 
|---|
|  | 513 | } | 
|---|
|  | 514 |  | 
|---|
|  | 515 | fd = newslot (); | 
|---|
|  | 516 |  | 
|---|
|  | 517 | if (fd == -1) | 
|---|
|  | 518 | { | 
|---|
|  | 519 | errno = EMFILE; | 
|---|
|  | 520 | return -1; | 
|---|
|  | 521 | } | 
|---|
|  | 522 |  | 
|---|
|  | 523 | /* It is an error to open a file that already exists. */ | 
|---|
|  | 524 | if ((flags & O_CREAT) && (flags & O_EXCL)) | 
|---|
|  | 525 | { | 
|---|
|  | 526 | struct stat st; | 
|---|
|  | 527 | int res; | 
|---|
|  | 528 | res = _stat (path, &st); | 
|---|
|  | 529 | if (res != -1) | 
|---|
|  | 530 | { | 
|---|
|  | 531 | errno = EEXIST; | 
|---|
|  | 532 | return -1; | 
|---|
|  | 533 | } | 
|---|
|  | 534 | } | 
|---|
|  | 535 |  | 
|---|
|  | 536 | /* The flags are Unix-style, so we need to convert them. */ | 
|---|
|  | 537 | #ifdef O_BINARY | 
|---|
|  | 538 | if (flags & O_BINARY) | 
|---|
|  | 539 | aflags |= 1; | 
|---|
|  | 540 | #endif | 
|---|
|  | 541 |  | 
|---|
|  | 542 | /* In O_RDONLY we expect aflags == 0. */ | 
|---|
|  | 543 |  | 
|---|
|  | 544 | if (flags & O_RDWR) | 
|---|
|  | 545 | aflags |= 2; | 
|---|
|  | 546 |  | 
|---|
|  | 547 | if ((flags & O_CREAT) || (flags & O_TRUNC) || (flags & O_WRONLY)) | 
|---|
|  | 548 | aflags |= 4; | 
|---|
|  | 549 |  | 
|---|
|  | 550 | if (flags & O_APPEND) | 
|---|
|  | 551 | { | 
|---|
|  | 552 | /* Can't ask for w AND a; means just 'a'.  */ | 
|---|
|  | 553 | aflags &= ~4; | 
|---|
|  | 554 | aflags |= 8; | 
|---|
|  | 555 | } | 
|---|
|  | 556 |  | 
|---|
|  | 557 | block[0] = POINTER_TO_PARAM_BLOCK_T (path); | 
|---|
|  | 558 | block[2] = strlen (path); | 
|---|
|  | 559 | block[1] = aflags; | 
|---|
|  | 560 |  | 
|---|
|  | 561 | fh = do_AngelSVC (AngelSVC_Reason_Open, block); | 
|---|
|  | 562 |  | 
|---|
|  | 563 | /* Return a user file descriptor or an error. */ | 
|---|
|  | 564 | if (fh >= 0) | 
|---|
|  | 565 | { | 
|---|
|  | 566 | openfiles[fd].handle = fh; | 
|---|
|  | 567 | openfiles[fd].flags = flags + 1; | 
|---|
|  | 568 | openfiles[fd].ino = ino++; | 
|---|
|  | 569 | openfiles[fd].pos = 0; | 
|---|
|  | 570 | return fd; | 
|---|
|  | 571 | } | 
|---|
|  | 572 | else | 
|---|
|  | 573 | return error (fh); | 
|---|
|  | 574 | } | 
|---|
|  | 575 |  | 
|---|
|  | 576 | int | 
|---|
|  | 577 | _open (const char *path, int flags, ...) | 
|---|
|  | 578 | { | 
|---|
|  | 579 | return _swiopen (path, flags); | 
|---|
|  | 580 | } | 
|---|
|  | 581 |  | 
|---|
|  | 582 | /* fh, is a valid internal file handle. */ | 
|---|
|  | 583 | int | 
|---|
|  | 584 | _swiclose (int fh) | 
|---|
|  | 585 | { | 
|---|
|  | 586 | param_block_t param[1]; | 
|---|
|  | 587 | param[0] = fh; | 
|---|
|  | 588 | return checkerror (do_AngelSVC (AngelSVC_Reason_Close, param)); | 
|---|
|  | 589 | } | 
|---|
|  | 590 |  | 
|---|
|  | 591 | /* fd, is a user file descriptor. */ | 
|---|
|  | 592 | int | 
|---|
|  | 593 | _close (int fd) | 
|---|
|  | 594 | { | 
|---|
|  | 595 | int res; | 
|---|
|  | 596 | struct fdent *pfd; | 
|---|
|  | 597 |  | 
|---|
|  | 598 | pfd = findslot (fd); | 
|---|
|  | 599 | if (pfd == NULL) | 
|---|
|  | 600 | { | 
|---|
|  | 601 | errno = EBADF; | 
|---|
|  | 602 | return -1; | 
|---|
|  | 603 | } | 
|---|
|  | 604 |  | 
|---|
|  | 605 | /* Handle stderr == stdout. */ | 
|---|
|  | 606 | if ((fd == 1 || fd == 2) && (openfiles[1].handle == openfiles[2].handle)) | 
|---|
|  | 607 | { | 
|---|
|  | 608 | pfd->handle = -1; | 
|---|
|  | 609 | return 0; | 
|---|
|  | 610 | } | 
|---|
|  | 611 |  | 
|---|
|  | 612 | /* Attempt to close the handle. */ | 
|---|
|  | 613 | res = _swiclose (pfd->handle); | 
|---|
|  | 614 |  | 
|---|
|  | 615 | /* Reclaim handle? */ | 
|---|
|  | 616 | if (res == 0) | 
|---|
|  | 617 | pfd->handle = -1; | 
|---|
|  | 618 |  | 
|---|
|  | 619 | return res; | 
|---|
|  | 620 | } | 
|---|
|  | 621 |  | 
|---|
|  | 622 | int __attribute__((weak)) | 
|---|
|  | 623 | _getpid (int n __attribute__ ((unused))) | 
|---|
|  | 624 | { | 
|---|
|  | 625 | return 1; | 
|---|
|  | 626 | } | 
|---|
|  | 627 |  | 
|---|
|  | 628 | /* Heap limit returned from SYS_HEAPINFO Angel semihost call.  */ | 
|---|
|  | 629 | ulong __heap_limit __attribute__ ((aligned (8))) = 0xcafedead; | 
|---|
|  | 630 |  | 
|---|
|  | 631 | caddr_t | 
|---|
|  | 632 | _sbrk (int incr) | 
|---|
|  | 633 | { | 
|---|
|  | 634 | extern char end asm ("end");  /* Defined by the linker.  */ | 
|---|
|  | 635 | static char *heap_end; | 
|---|
|  | 636 | char *prev_heap_end; | 
|---|
|  | 637 |  | 
|---|
|  | 638 | if (heap_end == NULL) | 
|---|
|  | 639 | heap_end = &end; | 
|---|
|  | 640 |  | 
|---|
|  | 641 | prev_heap_end = heap_end; | 
|---|
|  | 642 |  | 
|---|
|  | 643 | if ((heap_end + incr > stack_ptr) | 
|---|
|  | 644 | /* Honour heap limit if it's valid.  */ | 
|---|
|  | 645 | || ((__heap_limit != 0xcafedead) && (heap_end + incr > __heap_limit))) | 
|---|
|  | 646 | { | 
|---|
|  | 647 | /* Some of the libstdc++-v3 tests rely upon detecting | 
|---|
|  | 648 | out of memory errors, so do not abort here.  */ | 
|---|
|  | 649 | errno = ENOMEM; | 
|---|
|  | 650 | return (caddr_t) - 1; | 
|---|
|  | 651 | } | 
|---|
|  | 652 |  | 
|---|
|  | 653 | heap_end += incr; | 
|---|
|  | 654 |  | 
|---|
|  | 655 | return (caddr_t) prev_heap_end; | 
|---|
|  | 656 | } | 
|---|
|  | 657 |  | 
|---|
|  | 658 | int | 
|---|
|  | 659 | _swistat (int fd, struct stat *st) | 
|---|
|  | 660 | { | 
|---|
|  | 661 | struct fdent *pfd; | 
|---|
|  | 662 | param_block_t param[1]; | 
|---|
|  | 663 | int res; | 
|---|
|  | 664 |  | 
|---|
|  | 665 | pfd = findslot (fd); | 
|---|
|  | 666 | if (pfd == NULL) | 
|---|
|  | 667 | { | 
|---|
|  | 668 | errno = EBADF; | 
|---|
|  | 669 | return -1; | 
|---|
|  | 670 | } | 
|---|
|  | 671 |  | 
|---|
|  | 672 | param[0] = pfd->handle; | 
|---|
|  | 673 | res = do_AngelSVC (AngelSVC_Reason_IsTTY, param); | 
|---|
|  | 674 | if (res != 0 && res != 1) | 
|---|
|  | 675 | return error (-1); | 
|---|
|  | 676 |  | 
|---|
|  | 677 | memset (st, 0, sizeof (*st)); | 
|---|
|  | 678 |  | 
|---|
|  | 679 | if (res) | 
|---|
|  | 680 | { | 
|---|
|  | 681 | /* This is a tty. */ | 
|---|
|  | 682 | st->st_mode |= S_IFCHR; | 
|---|
|  | 683 | } | 
|---|
|  | 684 | else | 
|---|
|  | 685 | { | 
|---|
|  | 686 | /* This is a file, return the file length.  */ | 
|---|
|  | 687 | st->st_mode |= S_IFREG; | 
|---|
|  | 688 | res = checkerror (do_AngelSVC (AngelSVC_Reason_FLen, param)); | 
|---|
|  | 689 | if (res == -1) | 
|---|
|  | 690 | return -1; | 
|---|
|  | 691 | st->st_size = res; | 
|---|
|  | 692 | st->st_blksize = 1024; | 
|---|
|  | 693 | st->st_blocks = (res + 1023) / 1024; | 
|---|
|  | 694 | } | 
|---|
|  | 695 |  | 
|---|
|  | 696 | /* Deduce permissions based on mode in which file opened.  */ | 
|---|
|  | 697 | st->st_mode |= S_IRUSR | S_IRGRP | S_IROTH; | 
|---|
|  | 698 | if (pfd->flags & _FWRITE) | 
|---|
|  | 699 | st->st_mode |= S_IWUSR | S_IWGRP | S_IWOTH; | 
|---|
|  | 700 |  | 
|---|
|  | 701 | st->st_ino = pfd->ino; | 
|---|
|  | 702 | st->st_nlink = 1; | 
|---|
|  | 703 | return 0; | 
|---|
|  | 704 | } | 
|---|
|  | 705 |  | 
|---|
|  | 706 | int __attribute__((weak)) | 
|---|
|  | 707 | _fstat (int fd, struct stat * st) | 
|---|
|  | 708 | { | 
|---|
|  | 709 | return _swistat (fd, st); | 
|---|
|  | 710 | } | 
|---|
|  | 711 |  | 
|---|
|  | 712 | int __attribute__((weak)) | 
|---|
|  | 713 | _stat (const char *fname, struct stat *st) | 
|---|
|  | 714 | { | 
|---|
|  | 715 | int fd, res; | 
|---|
|  | 716 | /* The best we can do is try to open the file readonly. | 
|---|
|  | 717 | If it exists, then we can guess a few things about it. */ | 
|---|
|  | 718 | if ((fd = _open (fname, O_RDONLY)) == -1) | 
|---|
|  | 719 | return -1; | 
|---|
|  | 720 | res = _swistat (fd, st); | 
|---|
|  | 721 | /* Not interested in the error. */ | 
|---|
|  | 722 | _close (fd); | 
|---|
|  | 723 | return res; | 
|---|
|  | 724 | } | 
|---|
|  | 725 |  | 
|---|
|  | 726 | int __attribute__((weak)) | 
|---|
|  | 727 | _link (void) | 
|---|
|  | 728 | { | 
|---|
|  | 729 | errno = ENOSYS; | 
|---|
|  | 730 | return -1; | 
|---|
|  | 731 | } | 
|---|
|  | 732 |  | 
|---|
|  | 733 | int | 
|---|
|  | 734 | _unlink (const char *path) | 
|---|
|  | 735 | { | 
|---|
|  | 736 | int res; | 
|---|
|  | 737 | param_block_t block[2]; | 
|---|
|  | 738 | block[0] = POINTER_TO_PARAM_BLOCK_T (path); | 
|---|
|  | 739 | block[1] = strlen (path); | 
|---|
|  | 740 | res = do_AngelSVC (AngelSVC_Reason_Remove, block); | 
|---|
|  | 741 | if (res == -1) | 
|---|
|  | 742 | return error (res); | 
|---|
|  | 743 | return 0; | 
|---|
|  | 744 | } | 
|---|
|  | 745 |  | 
|---|
|  | 746 | int | 
|---|
|  | 747 | _gettimeofday (struct timeval *tp, void *tzvp) | 
|---|
|  | 748 | { | 
|---|
|  | 749 | struct timezone *tzp = tzvp; | 
|---|
|  | 750 | if (tp) | 
|---|
|  | 751 | { | 
|---|
|  | 752 | /* Ask the host for the seconds since the Unix epoch.  */ | 
|---|
|  | 753 | tp->tv_sec = do_AngelSVC (AngelSVC_Reason_Time, NULL); | 
|---|
|  | 754 | tp->tv_usec = 0; | 
|---|
|  | 755 | } | 
|---|
|  | 756 |  | 
|---|
|  | 757 | /* Return fixed data for the timezone.  */ | 
|---|
|  | 758 | if (tzp) | 
|---|
|  | 759 | { | 
|---|
|  | 760 | tzp->tz_minuteswest = 0; | 
|---|
|  | 761 | tzp->tz_dsttime = 0; | 
|---|
|  | 762 | } | 
|---|
|  | 763 |  | 
|---|
|  | 764 | return 0; | 
|---|
|  | 765 | } | 
|---|
|  | 766 |  | 
|---|
|  | 767 | /* Return a clock that ticks at 100Hz.  */ | 
|---|
|  | 768 | clock_t | 
|---|
|  | 769 | _clock (void) | 
|---|
|  | 770 | { | 
|---|
|  | 771 | clock_t timeval; | 
|---|
|  | 772 |  | 
|---|
|  | 773 | timeval = do_AngelSVC (AngelSVC_Reason_Clock, NULL); | 
|---|
|  | 774 | return timeval; | 
|---|
|  | 775 | } | 
|---|
|  | 776 |  | 
|---|
|  | 777 | /* Return a clock that ticks at 100Hz.  */ | 
|---|
|  | 778 | clock_t | 
|---|
|  | 779 | _times (struct tms * tp) | 
|---|
|  | 780 | { | 
|---|
|  | 781 | clock_t timeval = _clock (); | 
|---|
|  | 782 |  | 
|---|
|  | 783 | if (tp) | 
|---|
|  | 784 | { | 
|---|
|  | 785 | tp->tms_utime = timeval;  /* user time */ | 
|---|
|  | 786 | tp->tms_stime = 0;        /* system time */ | 
|---|
|  | 787 | tp->tms_cutime = 0;       /* user time, children */ | 
|---|
|  | 788 | tp->tms_cstime = 0;       /* system time, children */ | 
|---|
|  | 789 | } | 
|---|
|  | 790 |  | 
|---|
|  | 791 | return timeval; | 
|---|
|  | 792 | }; | 
|---|
|  | 793 |  | 
|---|
|  | 794 |  | 
|---|
|  | 795 | int | 
|---|
|  | 796 | _isatty (int fd) | 
|---|
|  | 797 | { | 
|---|
|  | 798 | struct fdent *pfd; | 
|---|
|  | 799 | param_block_t param[1]; | 
|---|
|  | 800 | int res; | 
|---|
|  | 801 |  | 
|---|
|  | 802 | /* Return 1 if fd is an open file descriptor referring to a terminal; | 
|---|
|  | 803 | otherwise 0 is returned, and errno is set to indicate the error.  */ | 
|---|
|  | 804 |  | 
|---|
|  | 805 | pfd = findslot (fd); | 
|---|
|  | 806 | if (pfd == NULL) | 
|---|
|  | 807 | { | 
|---|
|  | 808 | errno = EBADF; | 
|---|
|  | 809 | return 0; | 
|---|
|  | 810 | } | 
|---|
|  | 811 |  | 
|---|
|  | 812 | param[0] = pfd->handle; | 
|---|
|  | 813 | res = do_AngelSVC (AngelSVC_Reason_IsTTY, param); | 
|---|
|  | 814 |  | 
|---|
|  | 815 | if (res != 1) | 
|---|
|  | 816 | return error (0); | 
|---|
|  | 817 | return res; | 
|---|
|  | 818 | } | 
|---|
|  | 819 |  | 
|---|
|  | 820 | int | 
|---|
|  | 821 | _system (const char *s) | 
|---|
|  | 822 | { | 
|---|
|  | 823 | param_block_t block[2]; | 
|---|
|  | 824 | int e; | 
|---|
|  | 825 |  | 
|---|
|  | 826 | /* Hmmm.  The ARM debug interface specification doesn't say whether | 
|---|
|  | 827 | SYS_SYSTEM does the right thing with a null argument, or assign any | 
|---|
|  | 828 | meaning to its return value.  Try to do something reasonable....  */ | 
|---|
|  | 829 | if (!s) | 
|---|
|  | 830 | return 1;                   /* maybe there is a shell available? we can hope. :-P */ | 
|---|
|  | 831 | block[0] = POINTER_TO_PARAM_BLOCK_T (s); | 
|---|
|  | 832 | block[1] = strlen (s); | 
|---|
|  | 833 | e = checkerror (do_AngelSVC (AngelSVC_Reason_System, block)); | 
|---|
|  | 834 | if ((e >= 0) && (e < 256)) | 
|---|
|  | 835 | { | 
|---|
|  | 836 | /* We have to convert e, an exit status to the encoded status of | 
|---|
|  | 837 | the command.  To avoid hard coding the exit status, we simply | 
|---|
|  | 838 | loop until we find the right position.  */ | 
|---|
|  | 839 | int exit_code; | 
|---|
|  | 840 |  | 
|---|
|  | 841 | for (exit_code = e; e && WEXITSTATUS (e) != exit_code; e <<= 1) | 
|---|
|  | 842 | continue; | 
|---|
|  | 843 | } | 
|---|
|  | 844 | return e; | 
|---|
|  | 845 | } | 
|---|
|  | 846 |  | 
|---|
|  | 847 | int | 
|---|
|  | 848 | _rename (const char *oldpath, const char *newpath) | 
|---|
|  | 849 | { | 
|---|
|  | 850 | param_block_t block[4]; | 
|---|
|  | 851 | block[0] = POINTER_TO_PARAM_BLOCK_T (oldpath); | 
|---|
|  | 852 | block[1] = strlen (oldpath); | 
|---|
|  | 853 | block[2] = POINTER_TO_PARAM_BLOCK_T (newpath); | 
|---|
|  | 854 | block[3] = strlen (newpath); | 
|---|
|  | 855 | return checkerror (do_AngelSVC (AngelSVC_Reason_Rename, block)) ? -1 : 0; | 
|---|
|  | 856 | } | 
|---|
|  | 857 |  | 
|---|
|  | 858 | /* Returns the number of elapsed target ticks since the support code | 
|---|
|  | 859 | started execution. Returns -1 and sets errno on error.  */ | 
|---|
|  | 860 | long | 
|---|
|  | 861 | __aarch64_angel_elapsed (void) | 
|---|
|  | 862 | { | 
|---|
|  | 863 | int result; | 
|---|
|  | 864 | param_block_t block[2]; | 
|---|
|  | 865 | result = checkerror (do_AngelSVC (AngelSVC_Reason_Elapsed, block)); | 
|---|
|  | 866 | if (result == -1) | 
|---|
|  | 867 | return result; | 
|---|
|  | 868 | return block[0]; | 
|---|
|  | 869 | } | 
|---|