From: Kito Cheng <kito.cheng@gmail.com>
To: Craig Blackmore <craig.blackmore@embecosm.com>
Cc: Newlib <newlib@sourceware.org>, Keith Packard <keithp@keithp.com>
Subject: Re: [PATCH] RISC-V: Add semihosting support
Date: Mon, 30 Nov 2020 22:05:39 +0800 [thread overview]
Message-ID: <CA+yXCZD+Coc9aE9ddEw3qpd4BasE87UTB67z1gtzPwwSB7b03Q@mail.gmail.com> (raw)
In-Reply-To: <694d497b-bc07-a3ba-2643-a7336927e9a7@embecosm.com>
Hi Craig:
Thanks for your patch! I think the spec is kind of a de-facto
standard, which is implemented in openocd for a long time, so I think
it would be great to have newlib support for that!
I will review and test this patch this week and give feedback soon :)
On Mon, Nov 30, 2020 at 7:38 PM 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 <machine/syscall.h>
> +#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 <machine/syscall.h>
> +#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 <errno.h>
> +#include <fcntl.h>
> +#include <unistd.h>
> +
> +#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<RISCV_MAX_OPEN_FILES; 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<RISCV_MAX_OPEN_FILES; 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 <string.h>
> +#include <sys/stat.h>
> +#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 <machine/syscall.h>
> +#include <sys/timeb.h>
> +#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 <machine/syscall.h>
> +#include <sys/stat.h>
> +#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 <machine/syscall.h>
> +#include <errno.h>
> +#include <sys/types.h>
> +#include <unistd.h>
> +#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 <machine/syscall.h>
> +#include "semihost_syscall.h"
> +#include "semihost_fdtable.h"
> +#include <errno.h>
> +#include <string.h>
> +#include <fcntl.h>
> +
> +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 <machine/syscall.h>
> +#include <errno.h>
> +#include <sys/types.h>
> +#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 <machine/syscall.h>
> +#include <string.h>
> +#include <fcntl.h>
> +#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 <machine/syscall.h>
> +#include "semihost_syscall.h"
> +#include <sys/stat.h>
> +#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 <machine/syscall.h>
> +#include "semihost_syscall.h"
> +#include <string.h>
> +
> +/* 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 <machine/syscall.h>
> +#include <sys/types.h>
> +#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 <sys/types.h>
> +
> +#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 <sys/types.h>
> +
> +#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
>
>
next prev parent reply other threads:[~2020-11-30 14:05 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-11-30 11:36 Craig Blackmore
2020-11-30 14:05 ` Kito Cheng [this message]
2020-11-30 19:53 ` Jeff Johnston
2020-12-09 8:21 ` Kito Cheng
2020-12-15 12:00 ` Craig Blackmore
2020-12-15 22:51 ` Jeff Johnston
2020-12-16 8:33 ` Craig Blackmore
2020-12-16 8:43 ` Kito Cheng
2020-12-16 23:31 ` Jeff Johnston
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=CA+yXCZD+Coc9aE9ddEw3qpd4BasE87UTB67z1gtzPwwSB7b03Q@mail.gmail.com \
--to=kito.cheng@gmail.com \
--cc=craig.blackmore@embecosm.com \
--cc=keithp@keithp.com \
--cc=newlib@sourceware.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).