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