From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [63.128.21.124]) by sourceware.org (Postfix) with ESMTP id E590F393BC15 for ; Mon, 30 Nov 2020 19:53:52 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org E590F393BC15 Received: from mail-pl1-f198.google.com (mail-pl1-f198.google.com [209.85.214.198]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-440-7oEgB9SoORGXYdjiCFcPmw-1; Mon, 30 Nov 2020 14:53:48 -0500 X-MC-Unique: 7oEgB9SoORGXYdjiCFcPmw-1 Received: by mail-pl1-f198.google.com with SMTP id b4so8300457plr.15 for ; Mon, 30 Nov 2020 11:53:48 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to; bh=l6H7pfTfHllNtuw9HRhJzQogEhOL1aHLZA1zObmKSKk=; b=DSQ1AlXUIarDTUyjhfEjMMc85mvzjUoN7pLfvrAAdNb44beo782HF2kuQ2qTqk5CTx 3p1nDUcs01zVVxeEedHlljMuYu2IXUPP8zbeP+msaMxgB6hqAOWaOeV5uQ2N2z9EfPM4 lpw0OvtYACtlWsPRu53ZI6dB/apODrrVD3XKfdEh98HczfXicA/Zx3KbPhk9wJQHrfP/ 4gaJf4XScCkeniIipklOtq+Kxl+VlDy32new6WMOLQY8p3POstW15eGviW5j8OySC7U5 37hj8XbYUvWuyz9EHWrzXiu2vyCEge3RcoTtgBkV7P0F7nyLs9wQjnzy29Av/5FQGMlp Ah0Q== X-Gm-Message-State: AOAM532M/aQG9FZ6l9yn9IUM9dc44HZ9fqYuJqA1CSpC5cYHgTb2gSbi 1ZXXKyuORS3+0ByoYVIQ/WqYqMcBK0If0io5TFrnXPC/m8HG1DzciWjLONXePkvVt4jQJkdh/D+ KVTJZeCJul765qGVUgK42vL4Tu0bXHFQ= X-Received: by 2002:a17:902:820e:b029:d6:e802:75aa with SMTP id x14-20020a170902820eb02900d6e80275aamr19731051pln.51.1606766027298; Mon, 30 Nov 2020 11:53:47 -0800 (PST) X-Google-Smtp-Source: ABdhPJwHFSOWQlTGBqT5BemfPGMhzCXq+n/OEzqbquDSzNEvsIidZYvZ9YWqzRHxjTl5NFvSQwSjC6SNoS30vd1LUP8= X-Received: by 2002:a17:902:820e:b029:d6:e802:75aa with SMTP id x14-20020a170902820eb02900d6e80275aamr19731031pln.51.1606766026951; Mon, 30 Nov 2020 11:53:46 -0800 (PST) MIME-Version: 1.0 References: <694d497b-bc07-a3ba-2643-a7336927e9a7@embecosm.com> In-Reply-To: <694d497b-bc07-a3ba-2643-a7336927e9a7@embecosm.com> From: Jeff Johnston Date: Mon, 30 Nov 2020 14:53:35 -0500 Message-ID: Subject: Re: [PATCH] RISC-V: Add semihosting support To: Craig Blackmore , Newlib X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-11.5 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, HTML_MESSAGE, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org Content-Type: text/plain; charset="UTF-8" X-Content-Filtered-By: Mailman/MimeDel 2.1.29 X-BeenThere: newlib@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Newlib mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 30 Nov 2020 19:53:57 -0000 Hello Craig, Just a quick observation. There are no license details in any of the files you have submitted. Did you write the code or take it from somewhere else? If you wrote it, then please add the license and if you copied it, please use the license of the original code. Regards, -- Jeff J. On Mon, Nov 30, 2020 at 6:37 AM Craig Blackmore < craig.blackmore@embecosm.com> wrote: > Add a new library called libsemihost which implements syscalls using > semihosting syscalls. This is intended to be used instead of libgloss > when semihosting support is required. A new semihost.specs file has > been added which will link with -lsemihost instead -lgloss. > > The library is implemented following the RISC-V Semihosting > specification available at: > > https://github.com/riscv/riscv-semihosting-spec > > Tested on the gcc testsuite on rv32imc and rv64imc using spike and > openocd. > > --- > libgloss/riscv/Makefile.in | 66 +++++++++++++++++- > libgloss/riscv/machine/syscall.h | 25 +++++++ > libgloss/riscv/semihost-sys_close.c | 24 +++++++ > libgloss/riscv/semihost-sys_exit.c | 19 ++++++ > libgloss/riscv/semihost-sys_fdtable.c | 81 +++++++++++++++++++++++ > libgloss/riscv/semihost-sys_fstat.c | 15 +++++ > libgloss/riscv/semihost-sys_ftime.c | 12 ++++ > libgloss/riscv/semihost-sys_isatty.c | 17 +++++ > libgloss/riscv/semihost-sys_link.c | 5 ++ > libgloss/riscv/semihost-sys_lseek.c | 66 ++++++++++++++++++ > libgloss/riscv/semihost-sys_open.c | 58 ++++++++++++++++ > libgloss/riscv/semihost-sys_read.c | 28 ++++++++ > libgloss/riscv/semihost-sys_sbrk.c | 22 ++++++ > libgloss/riscv/semihost-sys_stat.c | 32 +++++++++ > libgloss/riscv/semihost-sys_stat_common.c | 32 +++++++++ > libgloss/riscv/semihost-sys_unlink.c | 11 +++ > libgloss/riscv/semihost-sys_write.c | 28 ++++++++ > libgloss/riscv/semihost.specs | 10 +++ > libgloss/riscv/semihost_fdtable.h | 17 +++++ > libgloss/riscv/semihost_stat.h | 10 +++ > libgloss/riscv/semihost_syscall.h | 43 ++++++++++++ > 21 files changed, 620 insertions(+), 1 deletion(-) > create mode 100644 libgloss/riscv/semihost-sys_close.c > create mode 100644 libgloss/riscv/semihost-sys_exit.c > create mode 100644 libgloss/riscv/semihost-sys_fdtable.c > create mode 100644 libgloss/riscv/semihost-sys_fstat.c > create mode 100644 libgloss/riscv/semihost-sys_ftime.c > create mode 100644 libgloss/riscv/semihost-sys_isatty.c > create mode 100644 libgloss/riscv/semihost-sys_link.c > create mode 100644 libgloss/riscv/semihost-sys_lseek.c > create mode 100644 libgloss/riscv/semihost-sys_open.c > create mode 100644 libgloss/riscv/semihost-sys_read.c > create mode 100644 libgloss/riscv/semihost-sys_sbrk.c > create mode 100644 libgloss/riscv/semihost-sys_stat.c > create mode 100644 libgloss/riscv/semihost-sys_stat_common.c > create mode 100644 libgloss/riscv/semihost-sys_unlink.c > create mode 100644 libgloss/riscv/semihost-sys_write.c > create mode 100644 libgloss/riscv/semihost.specs > create mode 100644 libgloss/riscv/semihost_fdtable.h > create mode 100644 libgloss/riscv/semihost_stat.h > create mode 100644 libgloss/riscv/semihost_syscall.h > > diff --git a/libgloss/riscv/Makefile.in b/libgloss/riscv/Makefile.in > index 579dd9554..185b6e6d2 100644 > --- a/libgloss/riscv/Makefile.in > +++ b/libgloss/riscv/Makefile.in > @@ -40,8 +40,38 @@ gloss_srcs = \ > sys_wait.c \ > sys_write.c > > +# libsemihost reuses some of the libgloss minimal implementations > + > +semihost_srcs = \ > + nanosleep.c \ > + sys_chdir.c \ > + sys_chmod.c \ > + sys_chown.c \ > + sys_execve.c \ > + sys_fork.c \ > + sys_getcwd.c \ > + sys_getpid.c \ > + sys_kill.c \ > + sys_utime.c \ > + sys_wait.c \ > + semihost-sys_close.c \ > + semihost-sys_exit.c \ > + semihost-sys_fdtable.c \ > + semihost-sys_fstat.c \ > + semihost-sys_ftime.c \ > + semihost-sys_isatty.c \ > + semihost-sys_link.c \ > + semihost-sys_lseek.c \ > + semihost-sys_open.c \ > + semihost-sys_read.c \ > + semihost-sys_sbrk.c \ > + semihost-sys_stat.c \ > + semihost-sys_stat_common.c \ > + semihost-sys_unlink.c \ > + semihost-sys_write.c > + > gloss_specs = \ > - nano.specs sim.specs > + nano.specs sim.specs semihost.specs > > # Extra files > > @@ -134,6 +164,17 @@ sim_objs += $(sim_c_objs) > deps += $(sim_c_deps) > junk += $(sim_c_deps) $(sim_c_objs) > > +semihost_c_srcs = $(filter %.c, $(semihost_srcs)) > +semihost_c_objs = $(patsubst %.c, semihost-%.o, $(notdir > $(semihost_c_srcs))) > +semihost_c_deps = $(patsubst %.c, semihost-%.d, $(notdir > $(semihost_c_srcs))) > + > +$(semihost_c_objs): semihost-%.o : %.c > + $(COMPILE) -c -o $@ $< > + > +semihost_objs += $(semihost_c_objs) > +deps += $(semihost_c_deps) > +junk += $(semihost_c_deps) $(semihost_c_objs) > + > #------------------------------------------------------------------------- > # Build Object Files from Assembly Source > #------------------------------------------------------------------------- > @@ -159,6 +200,16 @@ sim_objs += $(sim_asm_objs) > deps += $(sim_asm_deps) > junk += $(sim_asm_deps) $(sim_asm_objs) > > +semihost_asm_objs = $(patsubst %.S, semihost-%.o, $(notdir > $(gloss_asm_srcs))) > +semihost_asm_deps = $(patsubst %.S, semihost-%.d, $(notdir > $(gloss_asm_srcs))) > + > +$(semihost_asm_objs) : semihost-%.o : %.S > + $(COMPILE) -c -DUSING_SEMIHOST_SPECS -o $@ $< > + > +semihost_objs += $(semihost_asm_objs) > +deps += $(semihost_asm_deps) > +junk += $(semihost_asm_deps) $(semihost_asm_objs) > + > #------------------------------------------------------------------------- > # Build libgloss.a > #------------------------------------------------------------------------- > @@ -187,6 +238,19 @@ junk += $(sim_lib) > > install_libs += $(sim_lib) > > +#------------------------------------------------------------------------- > +# Build libsemihost.a > +#------------------------------------------------------------------------- > + > +semihost_lib = libsemihost.a > +$(semihost_lib) : $(semihost_objs) > + $(AR) rcv $@ $^ > + $(RANLIB) $@ > + > +junk += $(semihost_lib) > + > +install_libs += $(semihost_lib) > + > #------------------------------------------------------------------------- > # Build crt0.o > #------------------------------------------------------------------------- > diff --git a/libgloss/riscv/machine/syscall.h > b/libgloss/riscv/machine/syscall.h > index 5cd15b848..88b9fdfda 100644 > --- a/libgloss/riscv/machine/syscall.h > +++ b/libgloss/riscv/machine/syscall.h > @@ -54,4 +54,29 @@ > #define SYS_time 1062 > #define SYS_getmainvars 2011 > > +/* Semihosting operations. */ > +#define SEMIHOST_clock 0x10 > +#define SEMIHOST_close 0x02 > +#define SEMIHOST_elapsed 0x30 > +#define SEMIHOST_errno 0x13 > +#define SEMIHOST_exit 0x18 > +#define SEMIHOST_exit_extended 0x20 > +#define SEMIHOST_flen 0x0C > +#define SEMIHOST_get_cmdline 0x15 > +#define SEMIHOST_heapinfo 0x16 > +#define SEMIHOST_iserror 0x08 > +#define SEMIHOST_istty 0x09 > +#define SEMIHOST_open 0x01 > +#define SEMIHOST_read 0x06 > +#define SEMIHOST_readc 0x07 > +#define SEMIHOST_remove 0x0E > +#define SEMIHOST_rename 0x0F > +#define SEMIHOST_seek 0x0A > +#define SEMIHOST_system 0x12 > +#define SEMIHOST_tickfreq 0x31 > +#define SEMIHOST_time 0x11 > +#define SEMIHOST_tmpnam 0x0D > +#define SEMIHOST_write 0x05 > +#define SEMIHOST_writec 0x03 > +#define SEMIHOST_write0 0x04 > #endif > diff --git a/libgloss/riscv/semihost-sys_close.c > b/libgloss/riscv/semihost-sys_close.c > new file mode 100644 > index 000000000..214052185 > --- /dev/null > +++ b/libgloss/riscv/semihost-sys_close.c > @@ -0,0 +1,24 @@ > +#include > +#include "semihost_syscall.h" > +#include "semihost_fdtable.h" > + > +/* Close a file. */ > +int > +_close (int file) > +{ > + long res; > + struct fdentry *fd =__get_fdentry (file); > + long data_block[1]; > + > + if (fd == NULL) > + return -1; > + > + data_block[0] = fd->handle; > + res = syscall_errno (SEMIHOST_close, data_block); > + > + if (res != 0) > + return res; > + > + __remove_fdentry (file); > + return 0; > +} > diff --git a/libgloss/riscv/semihost-sys_exit.c > b/libgloss/riscv/semihost-sys_exit.c > new file mode 100644 > index 000000000..774ec847e > --- /dev/null > +++ b/libgloss/riscv/semihost-sys_exit.c > @@ -0,0 +1,19 @@ > +#include > +#include "semihost_syscall.h" > + > +#define ADP_Stopped_ApplicationExit 0x20026 > + > +/* Exit a program without cleaning up files. */ > +void > +_exit (int exit_status) > +{ > +#if __riscv_xlen == 32 > + syscall_errno (SEMIHOST_exit, (long *) ADP_Stopped_ApplicationExit); > +#else > + /* The semihosting exit operation only allows 64-bit targets to report > the > + exit code. */ > + long data_block[] = {ADP_Stopped_ApplicationExit, exit_status}; > + syscall_errno (SEMIHOST_exit, data_block); > +#endif > + while (1); > +} > diff --git a/libgloss/riscv/semihost-sys_fdtable.c > b/libgloss/riscv/semihost-sys_fdtable.c > new file mode 100644 > index 000000000..c9454224e > --- /dev/null > +++ b/libgloss/riscv/semihost-sys_fdtable.c > @@ -0,0 +1,81 @@ > +#include "semihost_fdtable.h" > +#include > +#include > +#include > + > +#ifndef RISCV_MAX_OPEN_FILES > +#define RISCV_MAX_OPEN_FILES 16 > +#endif > + > +extern int errno; > +extern int _open (const char *, int, ...); > + > +/* fdtable keeps track of the position of each file and is used to map > stdin, > + stdout and stderr to STDIN_FILENO, STDOUT_FILENO and STDERR_FILENO. */ > + > +static struct fdentry fdtable[RISCV_MAX_OPEN_FILES]; > + > +/* Initialize fdtable. A handle of -1 denotes an empty entry. */ > + > +void __attribute__ ((constructor)) > +init_semihosting () > +{ > + int handle; > + > + for (int i=0; i + fdtable[i].handle = -1; > + > + /* Set up std streams. */ > + /* stdin. */ > + handle = _open (":tt", O_RDONLY); > + fdtable[STDIN_FILENO].handle = handle; > + fdtable[STDIN_FILENO].pos = 0; > + > + /* stdout. */ > + handle = _open (":tt", O_WRONLY|O_CREAT|O_TRUNC); > + fdtable[STDOUT_FILENO].handle = handle; > + fdtable[STDOUT_FILENO].pos = 0; > + > + /* stderr. */ > + handle = _open (":tt", O_WRONLY|O_CREAT|O_APPEND); > + fdtable[STDERR_FILENO].handle = handle; > + fdtable[STDERR_FILENO].pos = 0; > +} > + > +/* Add entry to fdtable. */ > + > +int > +__add_fdentry (int handle) > +{ > + for (int i=0; i + if (fdtable[i].handle == -1) > + { > + fdtable[i].handle = handle; > + fdtable[i].pos = 0; > + return i; > + } > + /* Too many open files. */ > + errno = ENFILE; > + return -1; > +} > + > +/* Return the fdentry for file or NULL if not found. */ > + > +struct fdentry * > +__get_fdentry (int file) > +{ > + if (file<0 || file>RISCV_MAX_OPEN_FILES || fdtable[file].handle == -1) > + { > + errno = EBADF; > + return NULL; > + } > + return &fdtable[file]; > +} > + > +/* Remove entry from fdtable. */ > + > +void > +__remove_fdentry (int file) > +{ > + fdtable[file].handle = -1; > +} > diff --git a/libgloss/riscv/semihost-sys_fstat.c > b/libgloss/riscv/semihost-sys_fstat.c > new file mode 100644 > index 000000000..0c5a8d857 > --- /dev/null > +++ b/libgloss/riscv/semihost-sys_fstat.c > @@ -0,0 +1,15 @@ > +#include > +#include > +#include "semihost_stat.h" > + > +/* Status of an open file. The sys/stat.h header file required is > + distributed in the include subdirectory for this C library. */ > + > +int > +_fstat (int file, struct stat *st) > +{ > + /* Initialize st as not all fields will be set. */ > + memset (st, 0, sizeof (*st)); > + > + return __stat_common (file, st); > +} > diff --git a/libgloss/riscv/semihost-sys_ftime.c > b/libgloss/riscv/semihost-sys_ftime.c > new file mode 100644 > index 000000000..c8d9a9133 > --- /dev/null > +++ b/libgloss/riscv/semihost-sys_ftime.c > @@ -0,0 +1,12 @@ > +#include > +#include > +#include "semihost_syscall.h" > + > +/* Get the current time. */ > +int > +_ftime (struct timeb *tp) > +{ > + tp->time = syscall_errno (SEMIHOST_time, 0); > + tp->millitm = 0; > + return 0; > +} > diff --git a/libgloss/riscv/semihost-sys_isatty.c > b/libgloss/riscv/semihost-sys_isatty.c > new file mode 100644 > index 000000000..ed1376600 > --- /dev/null > +++ b/libgloss/riscv/semihost-sys_isatty.c > @@ -0,0 +1,17 @@ > +#include > +#include > +#include "semihost_syscall.h" > +#include "semihost_fdtable.h" > + > +int > +_isatty (int file) > +{ > + struct fdentry *fd =__get_fdentry (file); > + long data_block[1]; > + > + if (fd == NULL) > + return -1; > + > + data_block[0] = fd->handle; > + return syscall_errno (SEMIHOST_istty, data_block); > +} > diff --git a/libgloss/riscv/semihost-sys_link.c > b/libgloss/riscv/semihost-sys_link.c > new file mode 100644 > index 000000000..d65852e7e > --- /dev/null > +++ b/libgloss/riscv/semihost-sys_link.c > @@ -0,0 +1,5 @@ > +/* Establish a new name for an existing file. */ > +int _link (const char *old_name, const char *new_name) > +{ > + return -1; > +} > diff --git a/libgloss/riscv/semihost-sys_lseek.c > b/libgloss/riscv/semihost-sys_lseek.c > new file mode 100644 > index 000000000..121769243 > --- /dev/null > +++ b/libgloss/riscv/semihost-sys_lseek.c > @@ -0,0 +1,66 @@ > +#include > +#include > +#include > +#include > +#include "semihost_syscall.h" > +#include "semihost_fdtable.h" > + > +extern int errno; > + > +/* Set position in a file. */ > +off_t > +_lseek (int file, off_t offset, int dir) > +{ > + long data_block[2]; > + long flen; > + long res; > + struct fdentry *fd; > + off_t abs_pos; > + > + fd =__get_fdentry (file); > + if (fd == NULL) > + { > + errno = EBADF; > + return -1; > + } > + > + if (dir == SEEK_CUR && offset == 0) > + return fd->pos; > + > + data_block[0] = fd->handle; > + > + switch (dir) > + { > + case SEEK_SET: > + abs_pos = offset; > + break; > + case SEEK_CUR: > + abs_pos = fd->pos + offset; > + break; > + case SEEK_END: > + data_block[1] = 0; > + flen = syscall_errno (SEMIHOST_flen, data_block); > + if (flen == -1) > + return -1; > + abs_pos = flen + offset; > + break; > + default: > + errno = EINVAL; > + return -1; > + } > + > + if (abs_pos < 0) > + { > + errno = EINVAL; > + return -1; > + } > + > + data_block[1] = abs_pos; > + res = syscall_errno (SEMIHOST_seek, data_block); > + if (res == 0) > + { > + fd->pos = abs_pos; > + return abs_pos; > + } > + return res; > +} > diff --git a/libgloss/riscv/semihost-sys_open.c > b/libgloss/riscv/semihost-sys_open.c > new file mode 100644 > index 000000000..9d456a51e > --- /dev/null > +++ b/libgloss/riscv/semihost-sys_open.c > @@ -0,0 +1,58 @@ > +#include > +#include "semihost_syscall.h" > +#include "semihost_fdtable.h" > +#include > +#include > +#include > + > +extern int errno; > + > +#define SEMIHOST_MODE_R 0 > +#define SEMIHOST_MODE_RPLUS 2 > +#define SEMIHOST_MODE_W 4 > +#define SEMIHOST_MODE_WPLUS 6 > +#define SEMIHOST_MODE_A 8 > +#define SEMIHOST_MODE_APLUS 10 > + > +/* Open a file. */ > +int > +_open (const char *name, int flags, ...) > +{ > + int fh; > + int mode; > + long data_block[3]; > + > + /* Work out mode from flags. */ > + if ((flags & (O_RDONLY | O_WRONLY | O_RDWR)) == O_RDONLY) > + mode = SEMIHOST_MODE_R; > + else if ((flags & (O_WRONLY | O_CREAT | O_TRUNC)) > + == (O_WRONLY | O_CREAT | O_TRUNC)) > + mode = SEMIHOST_MODE_W; > + else if ((flags & (O_WRONLY | O_CREAT | O_APPEND)) > + == (O_WRONLY | O_CREAT | O_APPEND)) > + mode = SEMIHOST_MODE_A; > + else if ((flags & (O_RDWR | O_CREAT | O_TRUNC)) > + == (O_RDWR | O_CREAT | O_TRUNC)) > + mode = SEMIHOST_MODE_WPLUS; > + else if ((flags & (O_RDWR | O_CREAT | O_APPEND)) > + == (O_RDWR | O_CREAT | O_APPEND)) > + mode = SEMIHOST_MODE_APLUS; > + else if (flags & O_RDWR) > + mode = SEMIHOST_MODE_RPLUS; > + else > + { > + errno = EINVAL; > + return -1; > + } > + > + data_block[0] = (long) name; > + data_block[1] = mode; > + data_block[2] = strlen (name); > + fh = syscall_errno (SEMIHOST_open, data_block); > + /* Failed to open file. */ > + if (fh == -1) > + return -1; > + > + /* Register the file in the fdtable. */ > + return __add_fdentry (fh); > +} > diff --git a/libgloss/riscv/semihost-sys_read.c > b/libgloss/riscv/semihost-sys_read.c > new file mode 100644 > index 000000000..b76193301 > --- /dev/null > +++ b/libgloss/riscv/semihost-sys_read.c > @@ -0,0 +1,28 @@ > +#include > +#include > +#include > +#include "semihost_syscall.h" > +#include "semihost_fdtable.h" > + > +/* Read from a file. */ > +ssize_t _read (int file, void *ptr, size_t len) > +{ > + struct fdentry *fd =__get_fdentry (file); > + long data_block[3]; > + long res; > + > + if (fd == NULL) > + return -1; > + > + data_block[0] = fd->handle; > + data_block[1] = (long) ptr; > + data_block[2] = len; > + res = syscall_errno (SEMIHOST_read, data_block); > + if (res >= 0) > + { > + ssize_t bytes_read = len - res; > + fd->pos += bytes_read; > + return bytes_read; > + } > + return -1; > +} > diff --git a/libgloss/riscv/semihost-sys_sbrk.c > b/libgloss/riscv/semihost-sys_sbrk.c > new file mode 100644 > index 000000000..0d7cf3754 > --- /dev/null > +++ b/libgloss/riscv/semihost-sys_sbrk.c > @@ -0,0 +1,22 @@ > +/* Semihosting requires that sbrk be implemented without a syscall. */ > +extern char _end[]; /* _end is set in the linker command > file. */ > +char *heap_ptr; > + > +/* > + * sbrk -- changes heap size size. Get nbytes more > + * RAM. We just increment a pointer in what's > + * left of memory on the board. > + */ > +char * > +_sbrk (nbytes) > + int nbytes; > +{ > + char *base; > + > + if (!heap_ptr) > + heap_ptr = (char *)&_end; > + base = heap_ptr; > + heap_ptr += nbytes; > + > + return base; > +} > diff --git a/libgloss/riscv/semihost-sys_stat.c > b/libgloss/riscv/semihost-sys_stat.c > new file mode 100644 > index 000000000..09039b6e9 > --- /dev/null > +++ b/libgloss/riscv/semihost-sys_stat.c > @@ -0,0 +1,32 @@ > +#include > +#include > +#include > +#include "semihost_stat.h" > + > +/* Status of a file (by name). */ > + > +int > +_stat (const char *name, struct stat *st) > +{ > + int file; > + int res; > + > + /* Initialize st as not all fields will be set. */ > + memset (st, 0, sizeof (*st)); > + > + /* Try to open file. */ > + file = _open (name, O_RDONLY); > + if (file == -1) > + /* _open should have already set errno. */ > + return -1; > + > + /* File opened successfully, infer read permission for owner and assume > it is > + a regular file. */ > + st->st_mode |= S_IREAD | S_IFREG; > + > + /* Fill in more info. */ > + res = __stat_common (file, st); > + > + _close (file); > + return res; > +} > diff --git a/libgloss/riscv/semihost-sys_stat_common.c > b/libgloss/riscv/semihost-sys_stat_common.c > new file mode 100644 > index 000000000..aa7e716c2 > --- /dev/null > +++ b/libgloss/riscv/semihost-sys_stat_common.c > @@ -0,0 +1,32 @@ > +#include > +#include "semihost_syscall.h" > +#include > +#include "semihost_fdtable.h" > + > +/* Used by _fstat and _stat to fill in some common details. */ > + > +int > +__stat_common (int file, struct stat *st) > +{ > + int flen; > + struct fdentry *fd =__get_fdentry (file); > + long data_block[1]; > + > + if (fd == NULL) > + return -1; > + > + data_block[0] = fd->handle; > + > + /* Assume character device and default block size of 4096. */ > + st->st_mode |= S_IFCHR; > + st->st_blksize = 4096; > + > + /* Attempt to get length of file. */ > + flen = syscall_errno (SEMIHOST_flen, data_block); > + if (flen == -1) > + return -1; > + > + st->st_size = flen; > + > + return 0; > +} > diff --git a/libgloss/riscv/semihost-sys_unlink.c > b/libgloss/riscv/semihost-sys_unlink.c > new file mode 100644 > index 000000000..dd0d2e9b1 > --- /dev/null > +++ b/libgloss/riscv/semihost-sys_unlink.c > @@ -0,0 +1,11 @@ > +#include > +#include "semihost_syscall.h" > +#include > + > +/* Remove a file's directory entry. */ > +int > +_unlink (const char *name) > +{ > + long data_block[] = {(long) name, strlen (name)}; > + return syscall_errno (SEMIHOST_remove, data_block); > +} > diff --git a/libgloss/riscv/semihost-sys_write.c > b/libgloss/riscv/semihost-sys_write.c > new file mode 100644 > index 000000000..0a249c2b6 > --- /dev/null > +++ b/libgloss/riscv/semihost-sys_write.c > @@ -0,0 +1,28 @@ > +#include > +#include > +#include "semihost_syscall.h" > +#include "semihost_fdtable.h" > + > +/* Write to a file. */ > +ssize_t > +_write (int file, const void *ptr, size_t len) > +{ > + struct fdentry *fd =__get_fdentry (file); > + long data_block[3]; > + long res; > + > + if (fd == NULL) > + return -1; > + > + data_block[0] = fd->handle; > + data_block[1] = (long) ptr; > + data_block[2] = len; > + res = syscall_errno (SEMIHOST_write, data_block); > + if (res >= 0) > + { > + ssize_t bytes_written = len - res; > + fd->pos += bytes_written; > + return bytes_written; > + } > + return -1; > +} > diff --git a/libgloss/riscv/semihost.specs b/libgloss/riscv/semihost.specs > new file mode 100644 > index 000000000..1c86c67e4 > --- /dev/null > +++ b/libgloss/riscv/semihost.specs > @@ -0,0 +1,10 @@ > +# Spec file for semihosting syscalls. > + > +%rename lib semihost_lib > +%rename link semihost_link > + > +*lib: > +--start-group -lc -lsemihost --end-group > + > +*link: > +%(semihost_link) %:replace-outfile(-lgloss -lsemihost) > diff --git a/libgloss/riscv/semihost_fdtable.h > b/libgloss/riscv/semihost_fdtable.h > new file mode 100644 > index 000000000..0fa62dd2d > --- /dev/null > +++ b/libgloss/riscv/semihost_fdtable.h > @@ -0,0 +1,17 @@ > +#include > + > +#ifndef RISCV_SEMIHOST_FDTABLE_H > +#define RISCV_SEMIHOST_FDTABLE_H > + > +extern void __attribute__ ((constructor)) init_semihosting (); > +extern int __add_fdentry (int); > +extern struct fdentry * __get_fdentry (int); > +extern void __remove_fdentry (int); > + > +struct fdentry > +{ > + int handle; > + off_t pos; > +}; > + > +#endif > diff --git a/libgloss/riscv/semihost_stat.h > b/libgloss/riscv/semihost_stat.h > new file mode 100644 > index 000000000..2030c7ab2 > --- /dev/null > +++ b/libgloss/riscv/semihost_stat.h > @@ -0,0 +1,10 @@ > +#include > + > +#ifndef RISCV_SEMIHOST_STAT_H > +#define RISCV_SEMIHOST_STAT_H > + > +extern int __stat_common (int, struct stat *); > +extern int _open (const char *, int, ...); > +extern int _close (int); > + > +#endif > diff --git a/libgloss/riscv/semihost_syscall.h > b/libgloss/riscv/semihost_syscall.h > new file mode 100644 > index 000000000..c8ae9ffaf > --- /dev/null > +++ b/libgloss/riscv/semihost_syscall.h > @@ -0,0 +1,43 @@ > +#ifndef _INTERNAL_SYSCALL_H > +#define _INTERNAL_SYSCALL_H > + > +extern int errno; > + > +static inline long > +__semihost_syscall (long id, long *data_block) > +{ > + register long a0 asm ("a0") = id; > + register long a1 asm ("a1") = (long) data_block; > + > + /* RISC-V semihosting trap sequence. Must be uncompressed and must not > + cross page boundary. */ > + asm volatile ( > + ".balign 16 \n" > + ".option push \n" > + ".option norvc \n" > + "slli zero, zero, 0x1f \n" > + "ebreak \n" > + "srai zero, zero, 0x7 \n" > + ".option pop \n" > + : "+r"(a0) : "r"(a1) : "memory"); > + > + return a0; > +} > + > +static inline long > +__syscall_error () > +{ > + errno = __semihost_syscall (SEMIHOST_errno, 0); > + return -1; > +} > + > +static inline long > +syscall_errno (long id, long *data_block) > +{ > + long res = __semihost_syscall (id, data_block); > + if (res < 0) > + return __syscall_error (); > + return res; > +} > + > +#endif > -- > 2.17.1 > > >