public inbox for newlib@sourceware.org
 help / color / mirror / Atom feed
From: Jeff Johnston <jjohnstn@redhat.com>
To: Craig Blackmore <craig.blackmore@embecosm.com>
Cc: Newlib <newlib@sourceware.org>
Subject: Re: [PATCH] RISC-V: Add semihosting support
Date: Tue, 15 Dec 2020 17:51:55 -0500	[thread overview]
Message-ID: <CAOox84tU+8Tx-M6bB6cTFcj+TbwHvYKDCVfvhmozn9cb5ekbGA@mail.gmail.com> (raw)
In-Reply-To: <aee4f08e-6209-c656-4546-f488aa48e96c@embecosm.com>

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.

Thanks,

-- Jeff J.

On Tue, Dec 15, 2020 at 7:00 AM Craig Blackmore <
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
>
>
>

  reply	other threads:[~2020-12-15 22:52 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 [this message]
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=CAOox84tU+8Tx-M6bB6cTFcj+TbwHvYKDCVfvhmozn9cb5ekbGA@mail.gmail.com \
    --to=jjohnstn@redhat.com \
    --cc=craig.blackmore@embecosm.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).