[PATCH] RISC-V: Add semihosting support

Jeff Johnston jjohnstn@redhat.com
Wed Dec 16 23:31:38 GMT 2020


Patch merged to master with your license added to COPYING.LIBGLOSS.

-- Jeff J.

On Wed, Dec 16, 2020 at 3:33 AM Craig Blackmore <
craig.blackmore@embecosm.com> wrote:

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


More information about the Newlib mailing list