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