µOS++ IIIe Reference 7.0.0
The third edition of µOS++, a POSIX inspired open source framework, written in C++
Loading...
Searching...
No Matches
c-syscalls-semihosting.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the µOS++ distribution.
3 * (https://github.com/micro-os-plus)
4 * Copyright (c) 2015 Liviu Ionescu.
5 *
6 * Permission is hereby granted, free of charge, to any person
7 * obtaining a copy of this software and associated documentation
8 * files (the "Software"), to deal in the Software without
9 * restriction, including without limitation the rights to use,
10 * copy, modify, merge, publish, distribute, sublicense, and/or
11 * sell copies of the Software, and to permit persons to whom
12 * the Software is furnished to do so, subject to the following
13 * conditions:
14 *
15 * The above copyright notice and this permission notice shall be
16 * included in all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 * OTHER DEALINGS IN THE SOFTWARE.
26 */
27
28#if defined(__clang__)
29#pragma clang diagnostic ignored "-Wempty-translation-unit"
30#endif
31
32// ----------------------------------------------------------------------------
33
34#if defined(__ARM_EABI__)
35
36// ----------------------------------------------------------------------------
37
38#include <cmsis-plus/os-app-config.h>
40
41#if defined(OS_USE_SEMIHOSTING_SYSCALLS)
42
45
47
50
51#include "cmsis_device.h"
52
53#include <cstring>
54
55#include <cstdint>
56#include <cstdarg>
57#include <cerrno>
58
59#include <sys/fcntl.h>
60#include <sys/stat.h>
61#include <time.h>
62#include <sys/time.h>
63#include <sys/times.h>
64#include <ctype.h>
65#include <sys/wait.h>
66#include <unistd.h>
67
68// ----------------------------------------------------------------------------
69
70// Notes: Function prefix.
71//
72// To facilitate testing on POSIX platforms, and also to allow
73// integration on custom platforms, all function names are prefixed
74// with '__posix_'.
75// For embedded environments it is possible to also add aliases to the
76// standard, non-prefixed names, by adding the following preprocessor
77// definition: OS_INCLUDE_STANDARD_POSIX_FUNCTIONS
78
79// Notes: Reentrancy and 'errno'.
80//
81// The standard headers define errno as '*(__errno())';
82// In a multi-threaded environment, __errno() must return a
83// thread specific pointer.
84
85// Documentation:
86// http://infocenter.arm.com/help/topic/com.arm.doc.dui0205g/DUI0205.pdf
87
88// ----------------------------------------------------------------------------
89
90// Struct used to keep track of the file position, just so we
91// can implement fseek(fh,x,SEEK_CUR).
92struct fdent
93{
94 int handle;
95 int pos;
96};
97
98/*
99 * User file descriptors (fd) are integer indexes into
100 * the openfiles[] array. Error checking is done by using
101 * findslot().
102 *
103 * This openfiles array is manipulated directly by only
104 * these 5 functions:
105 *
106 * findslot() - Translate entry.
107 * newslot() - Find empty entry.
108 * initilise_monitor_handles() - Initialize entries.
109 * _swiopen() - Initialize entry.
110 * _close() - Handle stdout == stderr case.
111 *
112 * Every other function must use findslot().
113 */
114
115#if !defined(OS_INTEGER_SEMIHOSTING_MAX_OPEN_FILES)
116#define OS_INTEGER_SEMIHOSTING_MAX_OPEN_FILES (20)
117#endif
118
119static struct fdent openfiles[OS_INTEGER_SEMIHOSTING_MAX_OPEN_FILES];
120
121// ----------------------------------------------------------------------------
122// Support functions.
123
124// Return a pointer to the structure associated with
125// the user file descriptor fd.
126static struct fdent*
127__semihosting_findslot (int fd)
128{
129 // User file descriptor is out of range.
130 if ((unsigned int) fd >= OS_INTEGER_SEMIHOSTING_MAX_OPEN_FILES)
131 {
132 return nullptr;
133 }
134
135 // User file descriptor is open?
136 if (openfiles[fd].handle == -1)
137 {
138 return nullptr;
139 }
140
141 // Valid.
142 return &openfiles[fd];
143}
144
145// Return the next lowest numbered free file
146// structure, or -1 if we can't find one.
147static int
148__semihosting_newslot (void)
149{
150 int i;
151 for (i = 0; i < OS_INTEGER_SEMIHOSTING_MAX_OPEN_FILES; i++)
152 {
153 if (openfiles[i].handle == -1)
154 {
155 break;
156 }
157 }
158
160 {
161 return -1;
162 }
163
164 return i;
165}
166
167static int
168__semihosting_get_errno (void)
169{
170 return call_host (SEMIHOSTING_SYS_ERRNO, nullptr);
171}
172
173// Set errno and return result.
174static int
175__semihosting_error (int result)
176{
177 errno = __semihosting_get_errno ();
178 return result;
179}
180
181// Check the return and set errno appropriately.
182static int
183__semihosting_checkerror (int result)
184{
185 if (result == -1)
186 {
187 return __semihosting_error (-1);
188 }
189
190 return result;
191}
192
193/* fd, is a user file descriptor. */
194static int
195__semihosting_lseek (int fd, int ptr, int dir)
196{
197 struct fdent *pfd;
198
199 /* Valid file descriptor? */
200 pfd = __semihosting_findslot (fd);
201 if (pfd == NULL)
202 {
203 errno = EBADF;
204 return -1;
205 }
206
207 /* Valid whence? */
208 if ((dir != SEEK_CUR) && (dir != SEEK_SET) && (dir != SEEK_END))
209 {
210 errno = EINVAL;
211 return -1;
212 }
213
214 /* Convert SEEK_CUR to SEEK_SET */
215 if (dir == SEEK_CUR)
216 {
217 ptr = pfd->pos + ptr;
218 /* The resulting file offset would be negative. */
219 if (ptr < 0)
220 {
221 errno = EINVAL;
222 if ((pfd->pos > 0) && (ptr > 0))
223 {
224 errno = EOVERFLOW;
225 }
226 return -1;
227 }
228 dir = SEEK_SET;
229 }
230
231 int block[2];
232 int res;
233
234 if (dir == SEEK_END)
235 {
236 block[0] = pfd->handle;
237 res = __semihosting_checkerror (call_host (SEMIHOSTING_SYS_FLEN, block));
238 if (res == -1)
239 {
240 return -1;
241 }
242 ptr += res;
243 }
244
245 /* This code only does absolute seeks. */
246 block[0] = pfd->handle;
247 block[1] = ptr;
248 res = __semihosting_checkerror (call_host (SEMIHOSTING_SYS_SEEK, block));
249
250 /* At this point ptr is the current file position. */
251 if (res >= 0)
252 {
253 pfd->pos = ptr;
254 return ptr;
255 }
256 else
257 {
258 return -1;
259 }
260}
261
262static int
263__semihosting_stat (int fd, struct stat* st)
264{
265 struct fdent *pfd;
266 pfd = __semihosting_findslot (fd);
267 if (pfd == NULL)
268 {
269 errno = EBADF;
270 return -1;
271 }
272
273 /* Always assume a character device,
274 with 1024 byte blocks. */
275 st->st_mode |= S_IFCHR;
276 st->st_blksize = 1024;
277
278 int res;
279 res = __semihosting_checkerror (
280 call_host (SEMIHOSTING_SYS_FLEN, &pfd->handle));
281 if (res == -1)
282 {
283 return -1;
284 }
285
286 /* Return the file size. */
287 st->st_size = res;
288 return 0;
289}
290
291// ----------------------------------------------------------------------------
292// ---- POSIX IO functions ----------------------------------------------------
293
303int
304__posix_open (const char* path, int oflag, ...)
305{
306
307 int fd = __semihosting_newslot ();
308 if (fd == -1)
309 {
310 errno = EMFILE;
311 return -1;
312 }
313
314 /* It is an error to open a file that already exists. */
315 if ((oflag & O_CREAT) && (oflag & O_EXCL))
316 {
317 struct stat st;
318 int res;
319 res = __posix_stat (path, &st);
320 if (res != -1)
321 {
322 errno = EEXIST;
323 return -1;
324 }
325 }
326
327 int aflags = 0;
328 /* The flags are Unix-style, so we need to convert them. */
329#ifdef O_BINARY
330 if (oflag & O_BINARY)
331 {
332 aflags |= 1;
333 }
334#endif
335
336 /* In O_RDONLY we expect aflags == 0. */
337
338 if (oflag & O_RDWR)
339 {
340 aflags |= 2;
341 }
342
343 if ((oflag & O_CREAT) || (oflag & O_TRUNC) || (oflag & O_WRONLY))
344 {
345 aflags |= 4;
346 }
347
348 if (oflag & O_APPEND)
349 {
350 /* Can't ask for w AND a; means just 'a'. */
351 aflags &= ~4;
352 aflags |= 8;
353 }
354
355 uint32_t block[3];
356 block[0] = (uint32_t) path;
357 block[2] = std::strlen (path);
358 block[1] = (uint32_t) aflags;
359
360 int fh = call_host (SEMIHOSTING_SYS_OPEN, block);
361
362 /* Return a user file descriptor or an error. */
363 if (fh >= 0)
364 {
365 openfiles[fd].handle = fh;
366 openfiles[fd].pos = 0;
367 return fd;
368 }
369 else
370 {
371 return __semihosting_error (fh);
372 }
373}
374
375int
376__posix_close (int fildes)
377{
378 struct fdent *pfd;
379 pfd = __semihosting_findslot (fildes);
380 if (pfd == NULL)
381 {
382 errno = EBADF;
383 return -1;
384 }
385
386 // Handle stderr == stdout.
387 if ((fildes == 1 || fildes == 2)
388 && (openfiles[1].handle == openfiles[2].handle))
389 {
390 pfd->handle = -1;
391 return 0;
392 }
393
394 int block[1];
395 block[0] = pfd->handle;
396
397 // Attempt to close the handle.
398 int res;
399 res = __semihosting_checkerror (call_host (SEMIHOSTING_SYS_CLOSE, block));
400
401 // Reclaim handle?
402 if (res == 0)
403 {
404 pfd->handle = -1;
405 }
406
407 return res;
408}
409
410// ----------------------------------------------------------------------------
411
412// fd, is a valid user file handle.
413// Translates the return of SYS_READ into
414// bytes read.
415
416ssize_t
417__posix_read (int fildes, void* buf, size_t nbyte)
418{
419 struct fdent *pfd;
420 pfd = __semihosting_findslot (fildes);
421 if (pfd == NULL)
422 {
423 errno = EBADF;
424 return -1;
425 }
426
427 int block[3];
428 block[0] = pfd->handle;
429 block[1] = (int) buf;
430 block[2] = nbyte;
431
432 int res;
433 // Returns the number of bytes *not* written.
434 res = __semihosting_checkerror (call_host (SEMIHOSTING_SYS_READ, block));
435 if (res == -1)
436 {
437 return res;
438 }
439
440 pfd->pos += nbyte - res;
441
442 /* res == nbyte is not an error,
443 at least if we want feof() to work. */
444 return nbyte - res;
445}
446
447ssize_t
448__posix_write (int fildes, const void* buf, size_t nbyte)
449{
450 struct fdent *pfd;
451 pfd = __semihosting_findslot (fildes);
452 if (pfd == NULL)
453 {
454 errno = EBADF;
455 return -1;
456 }
457
458 int block[3];
459
460 block[0] = pfd->handle;
461 block[1] = (int) buf;
462 block[2] = nbyte;
463
464 // Returns the number of bytes *not* written.
465 int res;
466 res = __semihosting_checkerror (call_host (SEMIHOSTING_SYS_WRITE, block));
467 /* Clearly an error. */
468 if (res < 0)
469 {
470 return -1;
471 }
472
473 pfd->pos += nbyte - res;
474
475 // Did we write 0 bytes?
476 // Retrieve errno for just in case.
477 if ((nbyte - res) == 0)
478 {
479 return __semihosting_error (0);
480 }
481
482 return (nbyte - res);
483}
484
485off_t
486__posix_lseek (int fildes, off_t offset, int whence)
487{
488 return __semihosting_lseek (fildes, offset, whence);
489}
490
496int
497__posix_isatty (int fildes)
498{
499 struct fdent *pfd;
500 pfd = __semihosting_findslot (fildes);
501 if (pfd == NULL)
502 {
503 errno = EBADF;
504 return 0;
505 }
506
507 int tty;
508 tty = call_host (SEMIHOSTING_SYS_ISTTY, &pfd->handle);
509
510 if (tty == 1)
511 {
512 return 1;
513 }
514
515 errno = __semihosting_get_errno ();
516 return 0;
517}
518
519int
520__posix_fstat (int fildes, struct stat* buf)
521{
522 memset (buf, 0, sizeof(*buf));
523 return __semihosting_stat (fildes, buf);
524}
525
526// ----------------------------------------------------------------------------
527// ----- POSIX file functions -----
528
529int
530__posix_stat (const char* path, struct stat* buf)
531{
532 int fd;
533 memset (buf, 0, sizeof(*buf));
534 // The best we can do is try to open the file read only.
535 // If it exists, then we can guess a few things about it.
536 if ((fd = __posix_open (path, O_RDONLY)) == -1)
537 {
538 return -1;
539 }
540 buf->st_mode |= S_IFREG | S_IREAD;
541 int res = __semihosting_stat (fd, buf);
542 // Not interested in the error.
543 __posix_close (fd);
544 return res;
545}
546
547int
548__posix_rename (const char* existing, const char* _new)
549{
550 uint32_t block[4];
551 block[0] = (uint32_t) existing;
552 block[1] = std::strlen (existing);
553 block[2] = (uint32_t) _new;
554 block[3] = std::strlen (_new);
555 return
556 __semihosting_checkerror (call_host (SEMIHOSTING_SYS_RENAME, block)) ?
557 -1 : 0;
558}
559
560int
561__posix_unlink (const char* path)
562{
563 uint32_t block[2];
564 block[0] = (uint32_t) path;
565 block[1] = strlen (path);
566
567 int res;
568 res = call_host (SEMIHOSTING_SYS_REMOVE, block);
569 if (res == -1)
570 {
571 return __semihosting_error (res);
572 }
573 return 0;
574}
575
576int
577__posix_system (const char *command)
578{
579 // Hmmm. The ARM debug interface specification doesn't say whether
580 // SYS_SYSTEM does the right thing with a null argument, or assign any
581 // meaning to its return value. Try to do something reasonable....
582 if (command == nullptr)
583 {
584 return 1; // maybe there is a shell available? we can hope. :-P
585 }
586
587 uint32_t block[2];
588 block[0] = (uint32_t) command;
589 block[1] = strlen (command);
590 int e = __semihosting_checkerror (call_host (SEMIHOSTING_SYS_SYSTEM, block));
591 if ((e >= 0) && (e < 256))
592 {
593 // We have to convert e, an exit status to the encoded status of
594 // the command. To avoid hard coding the exit status, we simply
595 // loop until we find the right position.
596 int exit_code;
597
598 for (exit_code = e; (e != 0) && (WEXITSTATUS (e) != exit_code); e <<= 1)
599 {
600 continue;
601 }
602 }
603 return e;
604}
605
606int
607__posix_gettimeofday (struct timeval* ptimeval, void* ptimezone)
608{
609 struct timezone* tzp = (struct timezone*) ptimezone;
610 if (ptimeval)
611 {
612 // Ask the host for the seconds since the Unix epoch.
613 ptimeval->tv_sec = call_host (SEMIHOSTING_SYS_TIME, NULL);
614 ptimeval->tv_usec = 0;
615 }
616
617 // Return fixed data for the time zone.
618 if (tzp)
619 {
620 tzp->tz_minuteswest = 0;
621 tzp->tz_dsttime = 0;
622 }
623
624 return 0;
625}
626
627// Return a clock that ticks at 100Hz.
628clock_t
629__posix_clock (void)
630{
631 clock_t timeval;
632 timeval = (clock_t) call_host (SEMIHOSTING_SYS_CLOCK, NULL);
633
634 return timeval;
635}
636
637clock_t
638__posix_times (struct tms* buf)
639{
640 clock_t timeval = __posix_clock ();
641 if (buf)
642 {
643 buf->tms_utime = timeval; // user time
644 buf->tms_stime = 0; // system time
645 buf->tms_cutime = 0; // user time, children
646 buf->tms_cstime = 0; // system time, children
647 }
648
649 return timeval;
650}
651
652char*
653__posix_getcwd (char* buf, size_t size)
654{
655 // no cwd available via semihosting, so we use the temporary folder
656 strncpy (buf, "/tmp", size);
657 return buf;
658}
659
660#pragma GCC diagnostic push
661#pragma GCC diagnostic ignored "-Wunused-parameter"
662
663// ----------------------------------------------------------------------------
664// ----- POSIX file_system functions -----
665
666// Required by Google Tests
667int
668__posix_mkdir (const char* path, mode_t mode)
669{
670#if 0
671 // always return true
672 return 0;
673#else
674 errno = ENOSYS;
675 return -1;
676#endif
677}
678
679int
680__posix_rmdir (const char* path)
681{
682 errno = ENOSYS; // Not implemented
683 return -1;
684}
685
686void
687__posix_sync (void)
688{
689 errno = ENOSYS; // Not implemented
690}
691
692// ----------------------------------------------------------------------------
693// ----- Directories functions -----
694
695DIR*
696__posix_opendir (const char* dirpath)
697{
698 errno = ENOSYS; // Not implemented
699 return nullptr;
700}
701
702struct dirent*
703__posix_readdir (DIR* dirp)
704{
705 errno = ENOSYS; // Not implemented
706 return nullptr;
707}
708
709#if 0
710int
711__posix_readdir_r (DIR* dirp, struct dirent* entry, struct dirent** result)
712 {
713 errno = ENOSYS; // Not implemented
714 return ((ssize_t) -1);
715 }
716#endif
717
718void
720{
721 errno = ENOSYS; // Not implemented
722}
723
724int
725__posix_closedir (DIR* dirp)
726{
727 errno = ENOSYS; // Not implemented
728 return -1;
729}
730
731#pragma GCC diagnostic pop
732
733// ----------------------------------------------------------------------------
734// Socket functions
735
736#pragma GCC diagnostic push
737#pragma GCC diagnostic ignored "-Wunused-parameter"
738
739// socket() and socketpair() are the fuctions creating sockets.
740// The other are socket specific functions.
741
742// In addition, the following IO functions should work on sockets:
743// close(), read(), write(), writev(), ioctl(), fcntl(), select().
744
745int
746__posix_socket (int domain, int type, int protocol)
747{
748 errno = ENOSYS; // Not implemented
749 return -1;
750}
751
752#if 0
753int
754__posix_socketpair (int domain, int type, int protocol, int socket_vector[2])
755 {
756 errno = ENOSYS; // Not implemented
757 return -1;
758 }
759#endif
760
761int
762__posix_accept (int socket, struct sockaddr* address, socklen_t* address_len)
763{
764 errno = ENOSYS; // Not implemented
765 return -1;
766}
767
768int
769__posix_bind (int socket, const struct sockaddr* address, socklen_t address_len)
770{
771 errno = ENOSYS; // Not implemented
772 return -1;
773}
774
775int
776__posix_connect (int socket, const struct sockaddr* address,
777 socklen_t address_len)
778{
779 errno = ENOSYS; // Not implemented
780 return -1;
781}
782
783int
784__posix_getpeername (int socket, struct sockaddr* address,
785 socklen_t* address_len)
786{
787 errno = ENOSYS; // Not implemented
788 return -1;
789}
790
791int
792__posix_getsockname (int socket, struct sockaddr* address,
793 socklen_t* address_len)
794{
795 errno = ENOSYS; // Not implemented
796 return -1;
797}
798
799int
800__posix_getsockopt (int socket, int level, int option_name, void* option_value,
801 socklen_t* option_len)
802{
803 errno = ENOSYS; // Not implemented
804 return -1;
805}
806
807int
808__posix_listen (int socket, int backlog)
809{
810 errno = ENOSYS; // Not implemented
811 return -1;
812}
813
814ssize_t
815__posix_recv (int socket, void* buffer, size_t length, int flags)
816{
817 errno = ENOSYS; // Not implemented
818 return -1;
819}
820
821ssize_t
822__posix_recvfrom (int socket, void* buffer, size_t length, int flags,
823 struct sockaddr* address, socklen_t* address_len)
824{
825 errno = ENOSYS; // Not implemented
826 return -1;
827}
828
829ssize_t
830__posix_recvmsg (int socket, struct msghdr* message, int flags)
831{
832 errno = ENOSYS; // Not implemented
833 return -1;
834}
835
836ssize_t
837__posix_send (int socket, const void* buffer, size_t length, int flags)
838{
839 errno = ENOSYS; // Not implemented
840 return -1;
841}
842
843ssize_t
844__posix_sendmsg (int socket, const struct msghdr* message, int flags)
845{
846 errno = ENOSYS; // Not implemented
847 return -1;
848}
849
850ssize_t
851__posix_sendto (int socket, const void* message, size_t length, int flags,
852 const struct sockaddr* dest_addr, socklen_t dest_len)
853{
854 errno = ENOSYS; // Not implemented
855 return -1;
856}
857
858int
859__posix_setsockopt (int socket, int level, int option_name,
860 const void* option_value, socklen_t option_len)
861{
862 errno = ENOSYS; // Not implemented
863 return -1;
864}
865
866int
867__posix_shutdown (int socket, int how)
868{
869 errno = ENOSYS; // Not implemented
870 return -1;
871}
872
873int
875{
876 errno = ENOSYS; // Not implemented
877 return -1;
878}
879
880#pragma GCC diagnostic pop
881
882// ----------------------------------------------------------------------------
883
884// These functions are defined here to avoid linker errors in free
885// standing applications. They might be called in some error cases
886// from library code.
887//
888// If you detect other functions to be needed, just let us know
889// and we'll add them.
890
891// ----------------------------------------------------------------------------
892
893#pragma GCC diagnostic push
894#pragma GCC diagnostic ignored "-Wunused-parameter"
895
896// ----------------------------------------------------------------------------
897// Not yet implemented.
898
899int __attribute__((weak))
900__posix_readdir_r (DIR* dirp, struct dirent* entry, struct dirent** result)
901{
902 errno = ENOSYS; // Not implemented
903 return -1;
904}
905
906int __attribute__((weak))
907__posix_socketpair (int domain, int type, int protocol, int socket_vector[2])
908{
909 errno = ENOSYS; // Not implemented
910 return -1;
911}
912
913int
914__posix_select (int nfds, fd_set* readfds, fd_set* writefds, fd_set* errorfds,
915 struct timeval* timeout)
916{
917 errno = ENOSYS; // Not implemented
918 return -1;
919}
920
921int
922__posix_chdir (const char* path)
923{
924 errno = ENOSYS; // Not implemented
925 return -1;
926}
927
928// ----------------------------------------------------------------------------
929// Not available via semihosting.
930
931ssize_t
932__posix_writev (int fildes, const struct iovec* iov, int iovcnt)
933{
934 errno = ENOSYS; // Not implemented
935 return -1;
936}
937
938int
939__posix_ioctl (int fildes, int request, ...)
940{
941 errno = ENOSYS; // Not implemented
942 return -1;
943}
944
945int
946__posix_fcntl (int fildes, int cmd, ...)
947{
948 errno = ENOSYS; // Not implemented
949 return -1;
950}
951
952int
953__posix_ftruncate (int fildes, off_t length)
954{
955 errno = ENOSYS; // Not implemented
956 return -1;
957}
958
959int
960__posix_fsync (int fildes)
961{
962 errno = ENOSYS; // Not implemented
963 return -1;
964}
965
966int
967__posix_chmod (const char* path, mode_t mode)
968{
969 errno = ENOSYS; // Not implemented
970 return -1;
971}
972
973int
974__posix_tcdrain (int fildes)
975{
976 errno = ENOSYS; // Not implemented
977 return -1;
978}
979
980int
981__posix_tcgetattr (int fildes, struct termios *termios_p)
982{
983 errno = ENOSYS; // Not implemented
984 return -1;
985}
986
987int
988__posix_tcsetattr (int fildes, int optional_actions,
989 const struct termios *termios_p)
990{
991 errno = ENOSYS; // Not implemented
992 return -1;
993}
994
995int
996__posix_tcflush (int fildes, int queue_selector)
997{
998 errno = ENOSYS; // Not implemented
999 return -1;
1000}
1001
1002int
1003__posix_tcsendbreak (int fildes, int duration)
1004{
1005 errno = ENOSYS; // Not implemented
1006 return -1;
1007}
1008
1009int
1010__posix_truncate (const char* path, off_t length)
1011{
1012 errno = ENOSYS; // Not implemented
1013 return -1;
1014}
1015
1016int
1017__posix_utime (const char* path, const struct utimbuf* times)
1018{
1019 errno = ENOSYS; // Not implemented
1020 return -1;
1021}
1022
1023// ----------------------------------------------------------------------------
1024// Unavailable in non-Unix embedded environments.
1025
1026int
1027__posix_execve (const char* path, char* const argv[], char* const envp[])
1028{
1029 errno = ENOSYS; // Not implemented
1030 return -1;
1031}
1032
1033pid_t
1034__posix_fork (void)
1035{
1036 errno = ENOSYS; // Not implemented
1037 return ((pid_t) -1);
1038}
1039
1040pid_t
1041__posix_getpid (void)
1042{
1043 return 1;
1044}
1045
1046int
1047__posix_kill (pid_t pid, int sig)
1048{
1049 errno = ENOSYS; // Not implemented
1050 return -1;
1051}
1052
1053int
1054__posix_raise (int sig)
1055{
1056 errno = ENOSYS; // Not implemented
1057 return -1;
1058}
1059
1060pid_t
1061__posix_wait (int* stat_loc)
1062{
1063 errno = ENOSYS; // Not implemented
1064 return ((pid_t) -1);
1065}
1066
1067int
1068__posix_chown (const char* path, uid_t owner, gid_t group)
1069{
1070 errno = ENOSYS; // Not implemented
1071 return -1;
1072}
1073
1074int
1075__posix_link (const char* existing, const char* _new)
1076{
1077 errno = ENOSYS; // Not implemented
1078 return -1;
1079}
1080
1081int
1082__posix_symlink (const char* existing, const char* _new)
1083{
1084 errno = ENOSYS; // Not implemented
1085 return -1;
1086}
1087
1088ssize_t
1089__posix_readlink (const char* path, char* buf, size_t bufsize)
1090{
1091 errno = ENOSYS; // Not implemented
1092 return ((ssize_t) -1);
1093}
1094
1095int
1096__posix_statvfs (const char* path, struct statvfs* buf)
1097{
1098 errno = ENOSYS; // Not implemented
1099 return ((ssize_t) -1);
1100}
1101
1102int
1103__posix_fstatvfs (int fildes, struct statvfs* buf)
1104{
1105 errno = ENOSYS; // Not implemented
1106 return ((ssize_t) -1);
1107}
1108
1109#pragma GCC diagnostic pop
1110
1111// ----------------------------------------------------------------------------
1112
1113extern "C"
1114{
1115 void
1117}
1118
1119// ----------------------------------------------------------------------------
1120
1121void
1122__attribute__ ((noreturn,weak))
1123os_terminate (int code __attribute__((unused)))
1124{
1125 /* There is only one SWI for both _exit and _kill. For _exit, call
1126 the SWI with the second argument set to -1, an invalid value for
1127 signum, so that the SWI handler can distinguish the two calls.
1128 Note: The RDI implementation of _kill throws away both its
1129 arguments. */
1132 /* NOTREACHED */
1133}
1134
1135// ----------------------------------------------------------------------------
1136
1137// This is the semihosting implementation for the routine to
1138// process args.
1139// The entire command line is received from the host
1140// and parsed into strings.
1141
1142#define ARGS_BUF_ARRAY_SIZE 80
1143#define ARGV_BUF_ARRAY_SIZE 10
1144
1145typedef struct command_line_block_s
1146{
1147 char* command_line;
1148 int size;
1149} command_line_block_t;
1150
1151void
1152os_startup_initialize_args (int* p_argc, char*** p_argv)
1153{
1154 // Array of chars to receive the command line from the host.
1155 static char args_buf[ARGS_BUF_ARRAY_SIZE];
1156
1157 // Array of pointers to store the final argv pointers (pointing
1158 // in the above array).
1159 static char* argv_buf[ARGV_BUF_ARRAY_SIZE];
1160
1161 int argc = 0;
1162 int is_in_argument = 0;
1163
1164 command_line_block_t cmd_block;
1165 cmd_block.command_line = args_buf;
1166 cmd_block.size = sizeof(args_buf) - 1;
1167
1168 int ret = call_host (SEMIHOSTING_SYS_GET_CMDLINE, &cmd_block);
1169 if (ret == 0)
1170 {
1171 // In case the host send more than we can chew, limit the
1172 // string to our buffer.
1173 args_buf[ARGS_BUF_ARRAY_SIZE - 1] = '\0';
1174
1175 // The command line is a null terminated string.
1176 char* p = cmd_block.command_line;
1177
1178 int delim = '\0';
1179 int ch;
1180
1181 while ((ch = *p) != '\0')
1182 {
1183 if (is_in_argument == 0)
1184 {
1185 if (!isblank (ch))
1186 {
1187 if (argc
1188 >= (int) ((sizeof(argv_buf) / sizeof(argv_buf[0])) - 1))
1189 break;
1190
1191 if (ch == '"' || ch == '\'')
1192 {
1193 // Remember the delimiter to search for the
1194 // corresponding terminator.
1195 delim = ch;
1196 ++p; // skip the delimiter.
1197 ch = *p;
1198 }
1199 // Remember the arg beginning address.
1200 argv_buf[argc++] = p;
1201 is_in_argument = 1;
1202 }
1203 }
1204 else if (delim != '\0')
1205 {
1206 if ((ch == delim))
1207 {
1208 delim = '\0';
1209 *p = '\0';
1210 is_in_argument = 0;
1211 }
1212 }
1213 else if (isblank (ch))
1214 {
1215 delim = '\0';
1216 *p = '\0';
1217 is_in_argument = 0;
1218 }
1219 ++p;
1220 }
1221 }
1222
1223 if (argc == 0)
1224 {
1225 // No args found in string, return a single empty name.
1226 args_buf[0] = '\0';
1227 argv_buf[0] = &args_buf[0];
1228 ++argc;
1229 }
1230
1231 // Must end the array with a null pointer.
1232 argv_buf[argc] = NULL;
1233
1234 *p_argc = argc;
1235 *p_argv = &argv_buf[0];
1236
1237 // temporary here
1239
1240 return;
1241}
1242
1243static int monitor_stdin;
1244static int monitor_stdout;
1245static int monitor_stderr;
1246
1247// ----------------------------------------------------------------------------
1248
1249void
1251{
1252 // Open the standard file descriptors by opening the special
1253 // teletype device, ":tt", read-only to obtain a descriptor for
1254 // standard input and write-only to obtain a descriptor for standard
1255 // output. Finally, open ":tt" in append mode to obtain a descriptor
1256 // for standard error. Since this is a write mode, most kernels will
1257 // probably return the same value as for standard output, but the
1258 // kernel can differentiate the two using the mode flag and return a
1259 // different descriptor for standard error.
1260
1261 int volatile block[3];
1262
1263 block[0] = (int) ":tt";
1264 block[2] = 3; // length of filename
1265 block[1] = 0; // mode "r"
1266 monitor_stdin = call_host (SEMIHOSTING_SYS_OPEN, (void*) block);
1267
1268 block[0] = (int) ":tt";
1269 block[2] = 3; // length of filename
1270 block[1] = 4; // mode "w"
1271 monitor_stdout = call_host (SEMIHOSTING_SYS_OPEN, (void*) block);
1272
1273 block[0] = (int) ":tt";
1274 block[2] = 3; // length of filename
1275 block[1] = 8; // mode "a"
1276 monitor_stderr = call_host (SEMIHOSTING_SYS_OPEN, (void*) block);
1277
1278 // If we failed to open stderr, redirect to stdout.
1279 if (monitor_stderr == -1)
1280 {
1281 monitor_stderr = monitor_stdout;
1282 }
1283
1284 for (int i = 0; i < OS_INTEGER_SEMIHOSTING_MAX_OPEN_FILES; i++)
1285 {
1286 openfiles[i].handle = -1;
1287 }
1288
1289 openfiles[0].handle = monitor_stdin;
1290 openfiles[0].pos = 0;
1291 openfiles[1].handle = monitor_stdout;
1292 openfiles[1].pos = 0;
1293 openfiles[2].handle = monitor_stderr;
1294 openfiles[2].pos = 0;
1295}
1296
1297// ----------------------------------------------------------------------------
1298
1299#if (__STDC_HOSTED__ != 0)
1300
1301// The aliases must be in the same compilation unit as the names
1302// they alias.
1303
1304#if defined(OS_INCLUDE_NEWLIB_POSIX_FUNCTIONS)
1305
1306// For special embedded environment that use POSIX system calls
1307// with the newlib reentrant code, redefine
1308// some functions with _name(), others directly with name().
1309
1311
1312#else
1313
1314// For regular embedded environment that use POSIX system calls,
1315// redefine **all** functions without the '__posix_' prefix.
1316
1318
1319#endif
1320
1321#endif /* (__STDC_HOSTED__ != 0) */
1322#endif /* defined(OS_USE_SEMIHOSTING_SYSCALLS) */
1323
1324// ----------------------------------------------------------------------------
1325
1326#endif /* defined(__ARM_EABI__) */
1327
void initialise_monitor_handles(void)
#define OS_INTEGER_SEMIHOSTING_MAX_OPEN_FILES
Define the maximum number of semihosting open files.
void os_terminate(int code)
Terminate the application. There is no more life after this.
int stat(const char *path, struct stat *buf)
clock_t times(struct tms *buf)
int socket(int domain, int type, int protocol)
uint32_t socklen_t
#define __posix_select
#define __posix_sockatmark
#define __posix_wait
#define __posix_getsockopt
#define __posix_rewinddir
#define __posix_kill
#define __posix_lseek
#define __posix_chmod
#define __posix_chown
#define __posix_raise
#define __posix_shutdown
#define __posix_readlink
#define __posix_writev
#define __posix_truncate
#define __posix_fstat
#define __posix_stat
#define __posix_recvfrom
#define __posix_getcwd
#define __posix_readdir_r
#define __posix_close
#define __posix_recv
#define __posix_link
#define __posix_read
#define __posix_fcntl
#define __posix_sendto
#define __posix_symlink
#define __posix_getsockname
#define __posix_clock
#define __posix_gettimeofday
#define __posix_ioctl
#define __posix_setsockopt
#define __posix_socketpair
#define __posix_send
#define __posix_rmdir
#define __posix_times
#define __posix_readdir
#define __posix_closedir
#define __posix_write
#define __posix_listen
#define __posix_open
#define __posix_mkdir
#define __posix_rename
#define __posix_socket
#define __posix_isatty
#define __posix_unlink
#define __posix_recvmsg
#define __posix_ftruncate
#define __posix_accept
#define __posix_getpid
#define __posix_utime
#define __posix_bind
#define __posix_sync
#define __posix_opendir
#define __posix_fsync
#define __posix_connect
#define __posix_getpeername
#define __posix_system
#define __posix_chdir
#define __posix_fork
#define __posix_execve
#define __posix_sendmsg
static void report_exception(int reason)
@ ADP_Stopped_RunTimeError
Definition semihosting.h:64
@ SEMIHOSTING_SYS_WRITE
Definition semihosting.h:58
@ SEMIHOSTING_SYS_FLEN
Definition semihosting.h:43
@ SEMIHOSTING_SYS_GET_CMDLINE
Definition semihosting.h:44
@ SEMIHOSTING_SYS_REMOVE
Definition semihosting.h:51
@ SEMIHOSTING_SYS_SEEK
Definition semihosting.h:53
@ ADP_Stopped_ApplicationExit
Definition semihosting.h:63
@ SEMIHOSTING_SYS_TIME
Definition semihosting.h:56
@ SEMIHOSTING_SYS_CLOCK
Definition semihosting.h:40
@ SEMIHOSTING_SYS_ERRNO
Definition semihosting.h:42
@ SEMIHOSTING_SYS_ISTTY
Definition semihosting.h:47
@ SEMIHOSTING_SYS_READ
Definition semihosting.h:49
@ SEMIHOSTING_SYS_SYSTEM
Definition semihosting.h:54
@ SEMIHOSTING_SYS_CLOSE
Definition semihosting.h:39
@ SEMIHOSTING_SYS_OPEN
Definition semihosting.h:48
@ SEMIHOSTING_SYS_RENAME
Definition semihosting.h:52
static int call_host(int reason, void *arg)
Definition semihosting.h:99
Definition dirent.h:72
Definition uio.h:56
int __posix_tcgetattr(int fildes, struct termios *termios_p)
int __posix_statvfs(const char *path, struct statvfs *buf)
int __posix_tcflush(int fildes, int queue_selector)
int __posix_fstatvfs(int fildes, struct statvfs *buf)
void os_startup_initialize_args(int *p_argc, char ***p_argv)
Definition startup.cpp:419
int __posix_tcdrain(int fildes)
int __posix_tcsetattr(int fildes, int optional_actions, const struct termios *termios_p)
int __posix_tcsendbreak(int fildes, int duration)