From: Craig Blackmore <craig.blackmore@embecosm.com>
To: Jeff Johnston <jjohnstn@redhat.com>
Cc: Newlib <newlib@sourceware.org>
Subject: Re: [PATCH] RISC-V: Add semihosting support
Date: Wed, 16 Dec 2020 08:33:02 +0000 [thread overview]
Message-ID: <3ef25bfd-65d7-e8a2-cdd6-0b0532b5c4f6@embecosm.com> (raw)
In-Reply-To: <CAOox84tU+8Tx-M6bB6cTFcj+TbwHvYKDCVfvhmozn9cb5ekbGA@mail.gmail.com>
Hi Jeff,
On 15/12/2020 22:51, Jeff Johnston wrote:
> Hi Craig,
>
> Can you confirm that you have permission from your employer (embecosm)
> to contribute the code? Other than that, I think we're good to merge
> before the snapshot.
Yes, I have permission from Embecosm to contribute this.
Thanks,
Craig
>
> Thanks,
>
> -- Jeff J.
>
> On Tue, Dec 15, 2020 at 7:00 AM Craig Blackmore
> <craig.blackmore@embecosm.com <mailto:craig.blackmore@embecosm.com>>
> wrote:
>
> Hi Kito,
>
> Thanks for the test and review.
>
> On 09/12/2020 08:21, Kito Cheng wrote:
>
> > Hi Craig:
> >
> > I verified with GCC testsuite on qemu with Keith's semihosting
> patch,
> > And that's LGTM, only two minor review comment, see below:
> >
> >> +++ 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);
> > Could you use SEMIHOST_exit_extended here, so that we could have
> > return value on rv32.
>
> I can use SEMIHOST_exit_extended, but I will also need to add a
> check for the
> SH_EXT_EXIT_EXTENDED feature. Can I follow up with this in a later
> patch?
>
> >> +/* 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)
> > Should be >= RISCV_MAX_OPEN_FILES here?
>
> Please see updated patch below which fixes this condition and adds
> a license as
> requested by Jeff Johnston.
>
> Best wishes,
> Craig
>
> ---
> libgloss/riscv/Makefile.in | 66 +++++++++++++++++-
> libgloss/riscv/machine/syscall.h | 25 +++++++
> libgloss/riscv/semihost-sys_close.c | 28 ++++++++
> libgloss/riscv/semihost-sys_exit.c | 23 ++++++
> libgloss/riscv/semihost-sys_fdtable.c | 85
> +++++++++++++++++++++++
> libgloss/riscv/semihost-sys_fstat.c | 19 +++++
> libgloss/riscv/semihost-sys_ftime.c | 16 +++++
> libgloss/riscv/semihost-sys_isatty.c | 21 ++++++
> libgloss/riscv/semihost-sys_link.c | 9 +++
> libgloss/riscv/semihost-sys_lseek.c | 70 +++++++++++++++++++
> libgloss/riscv/semihost-sys_open.c | 62 +++++++++++++++++
> libgloss/riscv/semihost-sys_read.c | 32 +++++++++
> libgloss/riscv/semihost-sys_sbrk.c | 26 +++++++
> libgloss/riscv/semihost-sys_stat.c | 36 ++++++++++
> libgloss/riscv/semihost-sys_stat_common.c | 36 ++++++++++
> libgloss/riscv/semihost-sys_unlink.c | 15 ++++
> libgloss/riscv/semihost-sys_write.c | 32 +++++++++
> libgloss/riscv/semihost.specs | 10 +++
> libgloss/riscv/semihost_fdtable.h | 21 ++++++
> libgloss/riscv/semihost_stat.h | 14 ++++
> libgloss/riscv/semihost_syscall.h | 47 +++++++++++++
> 21 files changed, 692 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..47402340c
> --- /dev/null
> +++ b/libgloss/riscv/semihost-sys_close.c
> @@ -0,0 +1,28 @@
> +/*
> + * Copyright (C) 2020 Embecosm Limited
> + * SPDX-License-Identifier: BSD-2-Clause
> + */
> +#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..626fb6aeb
> --- /dev/null
> +++ b/libgloss/riscv/semihost-sys_exit.c
> @@ -0,0 +1,23 @@
> +/*
> + * Copyright (C) 2020 Embecosm Limited
> + * SPDX-License-Identifier: BSD-2-Clause
> + */
> +#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..152c92d15
> --- /dev/null
> +++ b/libgloss/riscv/semihost-sys_fdtable.c
> @@ -0,0 +1,85 @@
> +/*
> + * Copyright (C) 2020 Embecosm Limited
> + * SPDX-License-Identifier: BSD-2-Clause
> + */
> +#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..f57f0c07f
> --- /dev/null
> +++ b/libgloss/riscv/semihost-sys_fstat.c
> @@ -0,0 +1,19 @@
> +/*
> + * Copyright (C) 2020 Embecosm Limited
> + * SPDX-License-Identifier: BSD-2-Clause
> + */
> +#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..aeafc6ca2
> --- /dev/null
> +++ b/libgloss/riscv/semihost-sys_ftime.c
> @@ -0,0 +1,16 @@
> +/*
> + * Copyright (C) 2020 Embecosm Limited
> + * SPDX-License-Identifier: BSD-2-Clause
> + */
> +#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..02d8e39cb
> --- /dev/null
> +++ b/libgloss/riscv/semihost-sys_isatty.c
> @@ -0,0 +1,21 @@
> +/*
> + * Copyright (C) 2020 Embecosm Limited
> + * SPDX-License-Identifier: BSD-2-Clause
> + */
> +#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..717c5c81c
> --- /dev/null
> +++ b/libgloss/riscv/semihost-sys_link.c
> @@ -0,0 +1,9 @@
> +/*
> + * Copyright (C) 2020 Embecosm Limited
> + * SPDX-License-Identifier: BSD-2-Clause
> + */
> +/* 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..68fccf2ff
> --- /dev/null
> +++ b/libgloss/riscv/semihost-sys_lseek.c
> @@ -0,0 +1,70 @@
> +/*
> + * Copyright (C) 2020 Embecosm Limited
> + * SPDX-License-Identifier: BSD-2-Clause
> + */
> +#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..22f1d8206
> --- /dev/null
> +++ b/libgloss/riscv/semihost-sys_open.c
> @@ -0,0 +1,62 @@
> +/*
> + * Copyright (C) 2020 Embecosm Limited
> + * SPDX-License-Identifier: BSD-2-Clause
> + */
> +#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..3164eed56
> --- /dev/null
> +++ b/libgloss/riscv/semihost-sys_read.c
> @@ -0,0 +1,32 @@
> +/*
> + * Copyright (C) 2020 Embecosm Limited
> + * SPDX-License-Identifier: BSD-2-Clause
> + */
> +#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..cbd035832
> --- /dev/null
> +++ b/libgloss/riscv/semihost-sys_sbrk.c
> @@ -0,0 +1,26 @@
> +/*
> + * Copyright (C) 2020 Embecosm Limited
> + * SPDX-License-Identifier: BSD-2-Clause
> + */
> +/* 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..4015801b9
> --- /dev/null
> +++ b/libgloss/riscv/semihost-sys_stat.c
> @@ -0,0 +1,36 @@
> +/*
> + * Copyright (C) 2020 Embecosm Limited
> + * SPDX-License-Identifier: BSD-2-Clause
> + */
> +#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..b38eb0863
> --- /dev/null
> +++ b/libgloss/riscv/semihost-sys_stat_common.c
> @@ -0,0 +1,36 @@
> +/*
> + * Copyright (C) 2020 Embecosm Limited
> + * SPDX-License-Identifier: BSD-2-Clause
> + */
> +#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..1d2a6a0f9
> --- /dev/null
> +++ b/libgloss/riscv/semihost-sys_unlink.c
> @@ -0,0 +1,15 @@
> +/*
> + * Copyright (C) 2020 Embecosm Limited
> + * SPDX-License-Identifier: BSD-2-Clause
> + */
> +#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..9aee6d30b
> --- /dev/null
> +++ b/libgloss/riscv/semihost-sys_write.c
> @@ -0,0 +1,32 @@
> +/*
> + * Copyright (C) 2020 Embecosm Limited
> + * SPDX-License-Identifier: BSD-2-Clause
> + */
> +#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..f596a409a
> --- /dev/null
> +++ b/libgloss/riscv/semihost_fdtable.h
> @@ -0,0 +1,21 @@
> +/*
> + * Copyright (C) 2020 Embecosm Limited
> + * SPDX-License-Identifier: BSD-2-Clause
> + */
> +#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..c040fe8e7
> --- /dev/null
> +++ b/libgloss/riscv/semihost_stat.h
> @@ -0,0 +1,14 @@
> +/*
> + * Copyright (C) 2020 Embecosm Limited
> + * SPDX-License-Identifier: BSD-2-Clause
> + */
> +#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..50e731b40
> --- /dev/null
> +++ b/libgloss/riscv/semihost_syscall.h
> @@ -0,0 +1,47 @@
> +/*
> + * Copyright (C) 2020 Embecosm Limited
> + * SPDX-License-Identifier: BSD-2-Clause
> + */
> +#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-12-16 8:33 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
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 [this message]
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=3ef25bfd-65d7-e8a2-cdd6-0b0532b5c4f6@embecosm.com \
--to=craig.blackmore@embecosm.com \
--cc=jjohnstn@redhat.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).