public inbox for newlib@sourceware.org
 help / color / mirror / Atom feed
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
>
>

  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).