| NUC472_NUC442_BSP V3.03.003 The Board Support Package for NUC472/NUC442

_syscalls.c
Go to the documentation of this file.
1//
2// This file is part of the uOS++ III distribution
3// Parts of this file are from the newlib sources, issued under GPL.
4// Copyright (c) 2014 Liviu Ionescu
5//
6
7// ----------------------------------------------------------------------------
8
9 int errno;
10 void *__dso_handle __attribute__ ((weak));
11
12// ----------------------------------------------------------------------------
13
14#if !defined(OS_USE_SEMIHOSTING)
15
16#include <_ansi.h>
17#include <_syslist.h>
18#include <errno.h>
19//#include <sys/types.h>
20#include <sys/stat.h>
21#include <sys/time.h>
22#include <sys/times.h>
23#include <limits.h>
24#include <signal.h>
25
26 void
27__initialize_args(int* p_argc, char*** p_argv);
28
29// This is the standard default implementation for the routine to
30// process args. It returns a single empty arg.
31// For semihosting applications, this is redefined to get the real
32// args from the debugger. You can also use it if you decide to keep
33// some args in a non-volatile memory.
34
35 void __attribute__((weak))
36__initialize_args(int* p_argc, char*** p_argv)
37{
38 // By the time we reach this, the data and bss should have been initialised.
39
40 // The strings pointed to by the argv array shall be modifiable by the
41 // program, and retain their last-stored values between program startup
42 // and program termination. (static, no const)
43 static char name[] = "";
44
45 // The string pointed to by argv[0] represents the program name;
46 // argv[0][0] shall be the null character if the program name is not
47 // available from the host environment. argv[argc] shall be a null pointer.
48 // (static, no const)
49 static char* argv[2] =
50 { name, NULL };
51
52 *p_argc = 1;
53 *p_argv = &argv[0];
54 return;
55}
56
57// These functions are defined here to avoid linker errors in freestanding
58// applications. They might be called in some error cases from library
59// code.
60//
61// If you detect other functions to be needed, just let us know
62// and we'll add them.
63
64 int
65 raise(int sig __attribute__((unused)))
66{
67 errno = ENOSYS;
68 return -1;
69}
70
71 int
72 kill(pid_t pid, int sig);
73
74 int
75 kill(pid_t pid __attribute__((unused)), int sig __attribute__((unused)))
76{
77 errno = ENOSYS;
78 return -1;
79}
80
81#endif // !defined(OS_USE_SEMIHOSTING)
82
83// ----------------------------------------------------------------------------
84
85// If you need the empty definitions, remove the -ffreestanding option.
86
87#if __STDC_HOSTED__ == 1
88
89 char* __env[1] =
90{ 0 };
91 char** environ = __env;
92
93#if !defined(OS_USE_SEMIHOSTING)
94
95// Forward declarations
96
97 int
98_chown(const char* path, uid_t owner, gid_t group);
99
100 int
101_close(int fildes);
102
103 int
104_execve(char* name, char** argv, char** env);
105
106 int
107_fork(void);
108
109 int
110_fstat(int fildes, struct stat* st);
111
112 int
113_getpid(void);
114
115 int
116_gettimeofday(struct timeval* ptimeval, void* ptimezone);
117
118 int
119_isatty(int file);
120
121 int
122_kill(int pid, int sig);
123
124 int
125_link(char* existing, char* _new);
126
127 int
128_lseek(int file, int ptr, int dir);
129
130 int
131_open(char* file, int flags, int mode);
132
133 int
134_read(int file, char* ptr, int len);
135
136 int
137_readlink(const char* path, char* buf, size_t bufsize);
138
139 int
140_stat(const char* file, struct stat* st);
141
142 int
143_symlink(const char* path1, const char* path2);
144
145clock_t
146_times(struct tms* buf);
147
148 int
149_unlink(char* name);
150
151 int
152_wait(int* status);
153
154 int
155_write(int file, char* ptr, int len);
156
157// Definitions
158
159 int __attribute__((weak))
160_chown(const char* path __attribute__((unused)),
161 uid_t owner __attribute__((unused)), gid_t group __attribute__((unused)))
162{
163 errno = ENOSYS;
164 return -1;
165}
166
167 int __attribute__((weak))
168_close(int fildes __attribute__((unused)))
169{
170 errno = ENOSYS;
171 return -1;
172}
173
174 int __attribute__((weak))
175_execve(char* name __attribute__((unused)), char** argv __attribute__((unused)),
176 char** env __attribute__((unused)))
177{
178 errno = ENOSYS;
179 return -1;
180}
181
182 int __attribute__((weak))
183_fork(void)
184{
185 errno = ENOSYS;
186 return -1;
187}
188
189 int __attribute__((weak))
190_fstat(int fildes __attribute__((unused)),
191 struct stat* st __attribute__((unused)))
192{
193 errno = ENOSYS;
194 return -1;
195}
196
197 int __attribute__((weak))
198_getpid(void)
199{
200 errno = ENOSYS;
201 return -1;
202}
203
204 int __attribute__((weak))
205_gettimeofday(struct timeval* ptimeval __attribute__((unused)),
206 void* ptimezone __attribute__((unused)))
207{
208 errno = ENOSYS;
209 return -1;
210}
211
212 int __attribute__((weak))
213_isatty(int file __attribute__((unused)))
214{
215 errno = ENOSYS;
216 return 0;
217}
218
219 int __attribute__((weak))
220_kill(int pid __attribute__((unused)), int sig __attribute__((unused)))
221{
222 errno = ENOSYS;
223 return -1;
224}
225
226 int __attribute__((weak))
227_link(char* existing __attribute__((unused)),
228 char* _new __attribute__((unused)))
229{
230 errno = ENOSYS;
231 return -1;
232}
233
234 int __attribute__((weak))
235_lseek(int file __attribute__((unused)), int ptr __attribute__((unused)),
236 int dir __attribute__((unused)))
237{
238 errno = ENOSYS;
239 return -1;
240}
241
242 int __attribute__((weak))
243_open(char* file __attribute__((unused)), int flags __attribute__((unused)),
244 int mode __attribute__((unused)))
245{
246 errno = ENOSYS;
247 return -1;
248}
249
250 int __attribute__((weak))
251_read(int file __attribute__((unused)), char* ptr __attribute__((unused)),
252 int len __attribute__((unused)))
253{
254 errno = ENOSYS;
255 return -1;
256}
257
258 int __attribute__((weak))
259_readlink(const char* path __attribute__((unused)),
260 char* buf __attribute__((unused)), size_t bufsize __attribute__((unused)))
261{
262 errno = ENOSYS;
263 return -1;
264}
265
266 int __attribute__((weak))
267_stat(const char* file __attribute__((unused)),
268 struct stat* st __attribute__((unused)))
269{
270 errno = ENOSYS;
271 return -1;
272}
273
274 int __attribute__((weak))
275_symlink(const char* path1 __attribute__((unused)),
276 const char* path2 __attribute__((unused)))
277{
278 errno = ENOSYS;
279 return -1;
280}
281
282clock_t __attribute__((weak))
283_times(struct tms* buf __attribute__((unused)))
284{
285 errno = ENOSYS;
286 return ((clock_t) -1);
287}
288
289 int __attribute__((weak))
290_unlink(char* name __attribute__((unused)))
291{
292 errno = ENOSYS;
293 return -1;
294}
295
296 int __attribute__((weak))
297_wait(int* status __attribute__((unused)))
298{
299 errno = ENOSYS;
300 return -1;
301}
302
303 int __attribute__((weak))
304_write(int file __attribute__((unused)), char* ptr __attribute__((unused)),
305 int len __attribute__((unused)))
306{
307 errno = ENOSYS;
308 return -1;
309}
310
311// ----------------------------------------------------------------------------
312
313#else // defined(OS_USE_SEMIHOSTING)
314
315// ----------------------------------------------------------------------------
316
317/* Support files for GNU libc. Files in the system namespace go here.
318 Files in the C namespace (ie those that do not start with an
319 underscore) go in .c. */
320
321#include <_ansi.h>
322#include <stdint.h>
323//#include <sys/types.h>
324#include <sys/stat.h>
325#include <sys/fcntl.h>
326#include <stdio.h>
327#include <string.h>
328#include <time.h>
329#include <sys/time.h>
330#include <sys/times.h>
331#include <errno.h>
332#include <reent.h>
333#include <unistd.h>
334#include <sys/wait.h>
335#include <ctype.h>
336#include <signal.h>
337
338#include "semihosting.h"
339
340 int _kill (int pid, int sig);
341
342 void __attribute__((noreturn)) _exit (int status);
343
344// Forward declarations.
345 int _system (const char*);
346 int _rename (const char*, const char*);
347 int _isatty (int);
348clock_t _times (struct tms*);
349 int _gettimeofday (struct timeval *, void*);
350 int _unlink (const char*);
351 int _link (void);
352
353 int _stat (const char*, struct stat*);
354
355 int _fstat (int, struct stat*);
356 int _swistat (int fd, struct stat* st);
357 int _getpid (int);
358 int _close (int);
359clock_t _clock (void);
360 int _swiclose (int);
361 int _open (const char*, int, ...);
362 int _swiopen (const char*, int);
363 int _write (int, char*, int);
364 int _swiwrite (int, char*, int);
365 int _lseek (int, int, int);
366 int _swilseek (int, int, int);
367 int _read (int, char*, int);
368 int _swiread (int, char*, int);
369
370 void initialise_monitor_handles (void);
371
372 void __initialize_args (int* p_argc, char*** p_argv);
373
374 static int
375checkerror (int);
376 static int
377error (int);
378 static int
379get_errno (void);
380
381// ----------------------------------------------------------------------------
382
383#define ARGS_BUF_ARRAY_SIZE 80
384#define ARGV_BUF_ARRAY_SIZE 10
385
386 typedef struct
387{
388 char* pCommandLine;
389 int size;
390} CommandLineBlock;
391
392 void __initialize_args (int* p_argc, char*** p_argv)
393{
394 // Array of chars to receive the command line from the host
395 static char args_buf[ARGS_BUF_ARRAY_SIZE];
396
397 // Array of pointers to store the final argv pointers (pointing
398 // in the above array).
399 static char* argv_buf[ARGV_BUF_ARRAY_SIZE];
400
401 int argc = 0;
402 int isInArgument = 0;
403
404 CommandLineBlock cmdBlock;
405 cmdBlock.pCommandLine = args_buf;
406 cmdBlock.size = sizeof(args_buf) - 1;
407
408 int ret = call_host (SEMIHOSTING_SYS_GET_CMDLINE, &cmdBlock);
409 if (ret == 0)
410 {
411
412 // In case the host send more than we can chew, limit the
413 // string to our buffer.
414 args_buf[ARGS_BUF_ARRAY_SIZE - 1] = '\0';
415
416 // The command line is a null terminated string
417 char* p = cmdBlock.pCommandLine;
418
419 int delim = '\0';
420 int ch;
421
422 while ((ch = *p) != '\0')
423 {
424 if (isInArgument == 0)
425 {
426 if (!isblank(ch))
427 {
428 if (argc >= (int) ((sizeof(argv_buf) / sizeof(argv_buf[0])) - 1))
429 break;
430
431 if (ch == '"' || ch == '\'')
432 {
433 // Remember the delimiter to search for the
434 // corresponding terminator
435 delim = ch;
436 ++p; // skip the delimiter
437 ch = *p;
438 }
439 // Remember the arg beginning address
440 argv_buf[argc++] = p;
441 isInArgument = 1;
442 }
443 }
444 else if (delim != '\0')
445 {
446 if ((ch == delim))
447 {
448 delim = '\0';
449 *p = '\0';
450 isInArgument = 0;
451 }
452 }
453 else if (isblank(ch))
454 {
455 delim = '\0';
456 *p = '\0';
457 isInArgument = 0;
458 }
459 ++p;
460 }
461 }
462
463 if (argc == 0)
464 {
465 // No args found in string, return a single empty name.
466 args_buf[0] = '\0';
467 argv_buf[0] = &args_buf[0];
468 ++argc;
469 }
470
471 // Must end the array with a null pointer.
472 argv_buf[argc] = NULL;
473
474 *p_argc = argc;
475 *p_argv = &argv_buf[0];
476
477 // temporary here
478 initialise_monitor_handles ();
479
480 return;
481}
482
483// ----------------------------------------------------------------------------
484
485 void _exit (int status)
486{
487 /* There is only one SWI for both _exit and _kill. For _exit, call
488 the SWI with the second argument set to -1, an invalid value for
489 signum, so that the SWI handler can distinguish the two calls.
490 Note: The RDI implementation of _kill throws away both its
491 arguments. */
492 report_exception (status == 0 ? ADP_Stopped_ApplicationExit : ADP_Stopped_RunTimeError);
493}
494
495// ----------------------------------------------------------------------------
496
497 int __attribute__((weak))
498_kill (int pid __attribute__((unused)), int sig __attribute__((unused)))
499{
500 errno = ENOSYS;
501 return -1;
502}
503
504// ----------------------------------------------------------------------------
505
506/* Struct used to keep track of the file position, just so we
507 can implement fseek(fh,x,SEEK_CUR). */
508 struct fdent
509{
510 int handle;
511 int pos;
512};
513
514#define MAX_OPEN_FILES 20
515
516/* User file descriptors (fd) are integer indexes into
517 the openfiles[] array. Error checking is done by using
518 findslot().
519
520 This openfiles array is manipulated directly by only
521 these 5 functions:
522
523 findslot() - Translate entry.
524 newslot() - Find empty entry.
525 initilise_monitor_handles() - Initialize entries.
526 _swiopen() - Initialize entry.
527 _close() - Handle stdout == stderr case.
528
529 Every other function must use findslot(). */
530
531 static struct fdent openfiles[MAX_OPEN_FILES];
532
533 static struct fdent* findslot (int);
534 static int newslot (void);
535
536/* Register name faking - works in collusion with the linker. */
537 register char* stack_ptr asm ("sp");
538
539/* following is copied from libc/stdio/local.h to check std streams */
540 extern void __sinit(struct _reent*);
541#define CHECK_INIT(ptr) \
542 do \
543 { \
544 if ((ptr) && !(ptr)->__sdidinit) \
545 __sinit (ptr); \
546 } \
547 while (0)
548
549 static int monitor_stdin;
550 static int monitor_stdout;
551 static int monitor_stderr;
552
553/* Return a pointer to the structure associated with
554 the user file descriptor fd. */
555 static struct fdent*
556findslot (int fd)
557{
558 CHECK_INIT(_REENT);
559
560 /* User file descriptor is out of range. */
561 if ((unsigned int) fd >= MAX_OPEN_FILES)
562 {
563 return NULL;
564 }
565
566 /* User file descriptor is open? */
567 if (openfiles[fd].handle == -1)
568 {
569 return NULL;
570 }
571
572 /* Valid. */
573 return &openfiles[fd];
574}
575
576/* Return the next lowest numbered free file
577 structure, or -1 if we can't find one. */
578 static int
579newslot (void)
580{
581 int i;
582
583 for (i = 0; i < MAX_OPEN_FILES; i++)
584 {
585 if (openfiles[i].handle == -1)
586 {
587 break;
588 }
589 }
590
591 if (i == MAX_OPEN_FILES)
592 {
593 return -1;
594 }
595
596 return i;
597}
598
599 void
600initialise_monitor_handles (void)
601{
602 int i;
603
604 /* Open the standard file descriptors by opening the special
605 * teletype device, ":tt", read-only to obtain a descriptor for
606 * standard input and write-only to obtain a descriptor for standard
607 * output. Finally, open ":tt" in append mode to obtain a descriptor
608 * for standard error. Since this is a write mode, most kernels will
609 * probably return the same value as for standard output, but the
610 * kernel can differentiate the two using the mode flag and return a
611 * different descriptor for standard error.
612 */
613
614 int volatile block[3];
615
616 block[0] = (int) ":tt";
617 block[2] = 3; /* length of filename */
618 block[1] = 0; /* mode "r" */
619 monitor_stdin = call_host (SEMIHOSTING_SYS_OPEN, (void*) block);
620
621 block[0] = (int) ":tt";
622 block[2] = 3; /* length of filename */
623 block[1] = 4; /* mode "w" */
624 monitor_stdout = call_host (SEMIHOSTING_SYS_OPEN, (void*) block);
625
626 block[0] = (int) ":tt";
627 block[2] = 3; /* length of filename */
628 block[1] = 8; /* mode "a" */
629 monitor_stderr = call_host (SEMIHOSTING_SYS_OPEN, (void*) block);
630
631 /* If we failed to open stderr, redirect to stdout. */
632 if (monitor_stderr == -1)
633 {
634 monitor_stderr = monitor_stdout;
635 }
636
637 for (i = 0; i < MAX_OPEN_FILES; i++)
638 {
639 openfiles[i].handle = -1;
640 }
641
642 openfiles[0].handle = monitor_stdin;
643 openfiles[0].pos = 0;
644 openfiles[1].handle = monitor_stdout;
645 openfiles[1].pos = 0;
646 openfiles[2].handle = monitor_stderr;
647 openfiles[2].pos = 0;
648}
649
650 static int
651get_errno (void)
652{
653 return call_host (SEMIHOSTING_SYS_ERRNO, NULL);
654}
655
656/* Set errno and return result. */
657 static int
658error (int result)
659{
660 errno = get_errno ();
661 return result;
662}
663
664/* Check the return and set errno appropriately. */
665 static int
666checkerror (int result)
667{
668 if (result == -1)
669 {
670 return error (-1);
671 }
672
673 return result;
674}
675
676/* fh, is a valid internal file handle.
677 ptr, is a null terminated string.
678 len, is the length in bytes to read.
679 Returns the number of bytes *not* written. */
680 int
681_swiread (int fh, char* ptr, int len)
682{
683 int block[3];
684
685 block[0] = fh;
686 block[1] = (int) ptr;
687 block[2] = len;
688
689 return checkerror (call_host (SEMIHOSTING_SYS_READ, block));
690}
691
692/* fd, is a valid user file handle.
693 Translates the return of _swiread into
694 bytes read. */
695 int
696_read (int fd, char* ptr, int len)
697{
698 int res;
699 struct fdent *pfd;
700
701 pfd = findslot (fd);
702 if (pfd == NULL)
703 {
704 errno = EBADF;
705 return -1;
706 }
707
708 res = _swiread (pfd->handle, ptr, len);
709
710 if (res == -1)
711 {
712 return res;
713 }
714
715 pfd->pos += len - res;
716
717 /* res == len is not an error,
718 at least if we want feof() to work. */
719 return len - res;
720}
721
722/* fd, is a user file descriptor. */
723 int _swilseek (int fd, int ptr, int dir)
724{
725 int res;
726 struct fdent *pfd;
727
728 /* Valid file descriptor? */
729 pfd = findslot (fd);
730 if (pfd == NULL)
731 {
732 errno = EBADF;
733 return -1;
734 }
735
736 /* Valid whence? */
737 if ((dir != SEEK_CUR) && (dir != SEEK_SET) && (dir != SEEK_END))
738 {
739 errno = EINVAL;
740 return -1;
741 }
742
743 /* Convert SEEK_CUR to SEEK_SET */
744 if (dir == SEEK_CUR)
745 {
746 ptr = pfd->pos + ptr;
747 /* The resulting file offset would be negative. */
748 if (ptr < 0)
749 {
750 errno = EINVAL;
751 if ((pfd->pos > 0) && (ptr > 0))
752 {
753 errno = EOVERFLOW;
754 }
755 return -1;
756 }
757 dir = SEEK_SET;
758 }
759
760 int block[2];
761 if (dir == SEEK_END)
762 {
763 block[0] = pfd->handle;
764 res = checkerror (call_host (SEMIHOSTING_SYS_FLEN, block));
765 if (res == -1)
766 {
767 return -1;
768 }
769 ptr += res;
770 }
771
772 /* This code only does absolute seeks. */
773 block[0] = pfd->handle;
774 block[1] = ptr;
775 res = checkerror (call_host (SEMIHOSTING_SYS_SEEK, block));
776
777 /* At this point ptr is the current file position. */
778 if (res >= 0)
779 {
780 pfd->pos = ptr;
781 return ptr;
782 }
783 else
784 {
785 return -1;
786 }
787}
788
789 int _lseek (int fd, int ptr, int dir)
790{
791 return _swilseek (fd, ptr, dir);
792}
793
794/* fh, is a valid internal file handle.
795 Returns the number of bytes *not* written. */
796 int _swiwrite (int fh, char* ptr, int len)
797{
798 int block[3];
799
800 block[0] = fh;
801 block[1] = (int) ptr;
802 block[2] = len;
803
804 return checkerror (call_host (SEMIHOSTING_SYS_WRITE, block));
805}
806
807/* fd, is a user file descriptor. */
808 int _write (int fd, char* ptr, int len)
809{
810 int res;
811 struct fdent *pfd;
812
813 pfd = findslot (fd);
814 if (pfd == NULL)
815 {
816 errno = EBADF;
817 return -1;
818 }
819
820 res = _swiwrite (pfd->handle, ptr, len);
821
822 /* Clearly an error. */
823 if (res < 0)
824 {
825 return -1;
826 }
827
828 pfd->pos += len - res;
829
830 /* We wrote 0 bytes?
831 Retrieve errno just in case. */
832 if ((len - res) == 0)
833 {
834 return error (0);
835 }
836
837 return (len - res);
838}
839
840 int _swiopen (const char* path, int flags)
841{
842 int aflags = 0, fh;
843 uint32_t block[3];
844
845 int fd = newslot ();
846
847 if (fd == -1)
848 {
849 errno = EMFILE;
850 return -1;
851 }
852
853 /* It is an error to open a file that already exists. */
854 if ((flags & O_CREAT) && (flags & O_EXCL))
855 {
856 struct stat st;
857 int res;
858 res = _stat (path, &st);
859 if (res != -1)
860 {
861 errno = EEXIST;
862 return -1;
863 }
864 }
865
866 /* The flags are Unix-style, so we need to convert them. */
867#ifdef O_BINARY
868 if (flags & O_BINARY)
869 {
870 aflags |= 1;
871 }
872#endif
873
874 /* In O_RDONLY we expect aflags == 0. */
875
876 if (flags & O_RDWR)
877 {
878 aflags |= 2;
879 }
880
881 if ((flags & O_CREAT) || (flags & O_TRUNC) || (flags & O_WRONLY))
882 {
883 aflags |= 4;
884 }
885
886 if (flags & O_APPEND)
887 {
888 /* Can't ask for w AND a; means just 'a'. */
889 aflags &= ~4;
890 aflags |= 8;
891 }
892
893 block[0] = (uint32_t) path;
894 block[2] = strlen (path);
895 block[1] = (uint32_t) aflags;
896
897 fh = call_host (SEMIHOSTING_SYS_OPEN, block);
898
899 /* Return a user file descriptor or an error. */
900 if (fh >= 0)
901 {
902 openfiles[fd].handle = fh;
903 openfiles[fd].pos = 0;
904 return fd;
905 }
906 else
907 {
908 return error (fh);
909 }
910}
911
912 int _open (const char* path, int flags, ...)
913{
914 return _swiopen (path, flags);
915}
916
917/* fh, is a valid internal file handle. */
918 int _swiclose (int fh)
919{
920 return checkerror (call_host (SEMIHOSTING_SYS_CLOSE, &fh));
921}
922
923/* fd, is a user file descriptor. */
924 int _close (int fd)
925{
926 int res;
927 struct fdent *pfd;
928
929 pfd = findslot (fd);
930 if (pfd == NULL)
931 {
932 errno = EBADF;
933 return -1;
934 }
935
936 /* Handle stderr == stdout. */
937 if ((fd == 1 || fd == 2) && (openfiles[1].handle == openfiles[2].handle))
938 {
939 pfd->handle = -1;
940 return 0;
941 }
942
943 /* Attempt to close the handle. */
944 res = _swiclose (pfd->handle);
945
946 /* Reclaim handle? */
947 if (res == 0)
948 {
949 pfd->handle = -1;
950 }
951
952 return res;
953}
954
955 int __attribute__((weak))
956_getpid (int n __attribute__ ((unused)))
957{
958 return 1;
959}
960
961 int
962_swistat (int fd, struct stat* st)
963{
964 struct fdent *pfd;
965 int res;
966
967 pfd = findslot (fd);
968 if (pfd == NULL)
969 {
970 errno = EBADF;
971 return -1;
972 }
973
974 /* Always assume a character device,
975 with 1024 byte blocks. */
976 st->st_mode |= S_IFCHR;
977 st->st_blksize = 1024;
978 res = checkerror (call_host (SEMIHOSTING_SYS_FLEN, &pfd->handle));
979 if (res == -1)
980 {
981 return -1;
982 }
983
984 /* Return the file size. */
985 st->st_size = res;
986 return 0;
987}
988
989 int __attribute__((weak))
990_fstat (int fd, struct stat* st)
991{
992 memset (st, 0, sizeof(*st));
993 return _swistat (fd, st);
994}
995
996 int __attribute__((weak))
997_stat (const char*fname, struct stat *st)
998{
999 int fd, res;
1000 memset (st, 0, sizeof(*st));
1001 /* The best we can do is try to open the file readonly.
1002 If it exists, then we can guess a few things about it. */
1003 if ((fd = _open (fname, O_RDONLY)) == -1)
1004 {
1005 return -1;
1006 }
1007 st->st_mode |= S_IFREG | S_IREAD;
1008 res = _swistat (fd, st);
1009 /* Not interested in the error. */
1010 _close (fd);
1011 return res;
1012}
1013
1014 int __attribute__((weak))
1015_link (void)
1016{
1017 errno = ENOSYS;
1018 return -1;
1019}
1020
1021 int _unlink (const char* path)
1022{
1023 int res;
1024 uint32_t block[2];
1025 block[0] = (uint32_t) path;
1026 block[1] = strlen (path);
1027 res = call_host (SEMIHOSTING_SYS_REMOVE, block);
1028
1029 if (res == -1)
1030 {
1031 return error (res);
1032 }
1033 return 0;
1034}
1035
1036 int _gettimeofday (struct timeval* tp, void* tzvp)
1037{
1038 struct timezone* tzp = tzvp;
1039 if (tp)
1040 {
1041 /* Ask the host for the seconds since the Unix epoch. */
1042 tp->tv_sec = call_host (SEMIHOSTING_SYS_TIME, NULL);
1043 tp->tv_usec = 0;
1044 }
1045
1046 /* Return fixed data for the timezone. */
1047 if (tzp)
1048 {
1049 tzp->tz_minuteswest = 0;
1050 tzp->tz_dsttime = 0;
1051 }
1052
1053 return 0;
1054}
1055
1056/* Return a clock that ticks at 100Hz. */
1057clock_t _clock (void)
1058{
1059 clock_t timeval;
1060
1061 timeval = (clock_t) call_host (SEMIHOSTING_SYS_CLOCK, NULL);
1062 return timeval;
1063}
1064
1065/* Return a clock that ticks at 100Hz. */
1066clock_t
1067_times (struct tms* tp)
1068{
1069 clock_t timeval = _clock ();
1070
1071 if (tp)
1072 {
1073 tp->tms_utime = timeval; /* user time */
1074 tp->tms_stime = 0; /* system time */
1075 tp->tms_cutime = 0; /* user time, children */
1076 tp->tms_cstime = 0; /* system time, children */
1077 }
1078
1079 return timeval;
1080}
1081
1082 int _isatty (int fd)
1083{
1084 struct fdent *pfd;
1085 int tty;
1086
1087 pfd = findslot (fd);
1088 if (pfd == NULL)
1089 {
1090 errno = EBADF;
1091 return 0;
1092 }
1093
1094 tty = call_host (SEMIHOSTING_SYS_ISTTY, &pfd->handle);
1095
1096 if (tty == 1)
1097 {
1098 return 1;
1099 }
1100
1101 errno = get_errno ();
1102 return 0;
1103}
1104
1105 int _system (const char* s)
1106{
1107 uint32_t block[2];
1108 int e;
1109
1110 /* Hmmm. The ARM debug interface specification doesn't say whether
1111 SYS_SYSTEM does the right thing with a null argument, or assign any
1112 meaning to its return value. Try to do something reasonable.... */
1113 if (!s)
1114 {
1115 return 1; /* maybe there is a shell available? we can hope. :-P */
1116 }
1117 block[0] = (uint32_t) s;
1118 block[1] = strlen (s);
1119 e = checkerror (call_host (SEMIHOSTING_SYS_SYSTEM, block));
1120 if ((e >= 0) && (e < 256))
1121 {
1122 /* We have to convert e, an exit status to the encoded status of
1123 the command. To avoid hard coding the exit status, we simply
1124 loop until we find the right position. */
1125 int exit_code;
1126
1127 for (exit_code = e; e && WEXITSTATUS (e) != exit_code; e <<= 1)
1128 {
1129 continue;
1130 }
1131 }
1132 return e;
1133}
1134
1135 int _rename (const char* oldpath, const char* newpath)
1136{
1137 uint32_t block[4];
1138 block[0] = (uint32_t) oldpath;
1139 block[1] = strlen (oldpath);
1140 block[2] = (uint32_t) newpath;
1141 block[3] = strlen (newpath);
1142 return checkerror (call_host (SEMIHOSTING_SYS_RENAME, block)) ? -1 : 0;
1143}
1144
1145// ----------------------------------------------------------------------------
1146// Required by Google Tests
1147
1148 int mkdir (const char *path __attribute__((unused)), mode_t mode __attribute__((unused)))
1149{
1150#if 0
1151 // always return true
1152 return 0;
1153#else
1154 errno = ENOSYS;
1155 return -1;
1156#endif
1157}
1158
1159 char *getcwd (char *buf, size_t size)
1160{
1161 // no cwd available via semihosting, so we use the temporary folder
1162 strncpy (buf, "/tmp", size);
1163 return buf;
1164}
1165
1166#endif // defined OS_USE_SEMIHOSTING
1167
1168#endif // __STDC_HOSTED__ == 1
__attribute__
void *__dso_handle __attribute__((weak))
Definition: _syscalls.c:35
__initialize_args
void __initialize_args(int *p_argc, char ***p_argv)
kill
int kill(pid_t pid, int sig)
raise
int raise(int sig __attribute__((unused)))
Definition: _syscalls.c:65
errno
int errno
Definition: _syscalls.c:9
NULL
#define NULL
NULL pointer.
Definition: NUC472_442.h:29018
semihosting.h
ADP_Stopped_RunTimeError
@ ADP_Stopped_RunTimeError
Definition: semihosting.h:38
SEMIHOSTING_SYS_WRITE
@ SEMIHOSTING_SYS_WRITE
Definition: semihosting.h:32
SEMIHOSTING_SYS_FLEN
@ SEMIHOSTING_SYS_FLEN
Definition: semihosting.h:17
SEMIHOSTING_SYS_GET_CMDLINE
@ SEMIHOSTING_SYS_GET_CMDLINE
Definition: semihosting.h:18
SEMIHOSTING_SYS_REMOVE
@ SEMIHOSTING_SYS_REMOVE
Definition: semihosting.h:25
SEMIHOSTING_SYS_SEEK
@ SEMIHOSTING_SYS_SEEK
Definition: semihosting.h:27
ADP_Stopped_ApplicationExit
@ ADP_Stopped_ApplicationExit
Definition: semihosting.h:37
SEMIHOSTING_SYS_TIME
@ SEMIHOSTING_SYS_TIME
Definition: semihosting.h:30
SEMIHOSTING_SYS_CLOCK
@ SEMIHOSTING_SYS_CLOCK
Definition: semihosting.h:14
SEMIHOSTING_SYS_ERRNO
@ SEMIHOSTING_SYS_ERRNO
Definition: semihosting.h:16
SEMIHOSTING_SYS_ISTTY
@ SEMIHOSTING_SYS_ISTTY
Definition: semihosting.h:21
SEMIHOSTING_SYS_READ
@ SEMIHOSTING_SYS_READ
Definition: semihosting.h:23
SEMIHOSTING_SYS_SYSTEM
@ SEMIHOSTING_SYS_SYSTEM
Definition: semihosting.h:28
SEMIHOSTING_SYS_CLOSE
@ SEMIHOSTING_SYS_CLOSE
Definition: semihosting.h:13
SEMIHOSTING_SYS_OPEN
@ SEMIHOSTING_SYS_OPEN
Definition: semihosting.h:22
SEMIHOSTING_SYS_RENAME
@ SEMIHOSTING_SYS_RENAME
Definition: semihosting.h:26