[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