From: Craig Blackmore <craig.blackmore@embecosm.com>
To: Kito Cheng <kito.cheng@gmail.com>
Cc: Newlib <newlib@sourceware.org>
Subject: Re: [PATCH] RISC-V: Add semihosting support
Date: Tue, 15 Dec 2020 12:00:27 +0000 [thread overview]
Message-ID: <aee4f08e-6209-c656-4546-f488aa48e96c@embecosm.com> (raw)
In-Reply-To: <CA+yXCZD0ZNUNob0srvDQvefwO7C+AvqOfwSrLgZ0c76-ZDBg3A@mail.gmail.com>
Hi Kito,
Thanks for the test and review.
On 09/12/2020 08:21, Kito Cheng wrote:
> Hi Craig:
>
> I verified with GCC testsuite on qemu with Keith's semihosting patch,
> And that's LGTM, only two minor review comment, see below:
>
>> +++ b/libgloss/riscv/semihost-sys_exit.c
>> @@ -0,0 +1,19 @@
>> +#include <machine/syscall.h>
>> +#include "semihost_syscall.h"
>> +
>> +#define ADP_Stopped_ApplicationExit 0x20026
>> +
>> +/* Exit a program without cleaning up files. */
>> +void
>> +_exit (int exit_status)
>> +{
>> +#if __riscv_xlen == 32
>> + syscall_errno (SEMIHOST_exit, (long *) ADP_Stopped_ApplicationExit);
> Could you use SEMIHOST_exit_extended here, so that we could have
> return value on rv32.
I can use SEMIHOST_exit_extended, but I will also need to add a check for the
SH_EXT_EXIT_EXTENDED feature. Can I follow up with this in a later patch?
>> +/* Return the fdentry for file or NULL if not found. */
>> +
>> +struct fdentry *
>> +__get_fdentry (int file)
>> +{
>> + if (file<0 || file>RISCV_MAX_OPEN_FILES || fdtable[file].handle == -1)
> Should be >= RISCV_MAX_OPEN_FILES here?
Please see updated patch below which fixes this condition and adds a license as
requested by Jeff Johnston.
Best wishes,
Craig
---
libgloss/riscv/Makefile.in | 66 +++++++++++++++++-
libgloss/riscv/machine/syscall.h | 25 +++++++
libgloss/riscv/semihost-sys_close.c | 28 ++++++++
libgloss/riscv/semihost-sys_exit.c | 23 ++++++
libgloss/riscv/semihost-sys_fdtable.c | 85 +++++++++++++++++++++++
libgloss/riscv/semihost-sys_fstat.c | 19 +++++
libgloss/riscv/semihost-sys_ftime.c | 16 +++++
libgloss/riscv/semihost-sys_isatty.c | 21 ++++++
libgloss/riscv/semihost-sys_link.c | 9 +++
libgloss/riscv/semihost-sys_lseek.c | 70 +++++++++++++++++++
libgloss/riscv/semihost-sys_open.c | 62 +++++++++++++++++
libgloss/riscv/semihost-sys_read.c | 32 +++++++++
libgloss/riscv/semihost-sys_sbrk.c | 26 +++++++
libgloss/riscv/semihost-sys_stat.c | 36 ++++++++++
libgloss/riscv/semihost-sys_stat_common.c | 36 ++++++++++
libgloss/riscv/semihost-sys_unlink.c | 15 ++++
libgloss/riscv/semihost-sys_write.c | 32 +++++++++
libgloss/riscv/semihost.specs | 10 +++
libgloss/riscv/semihost_fdtable.h | 21 ++++++
libgloss/riscv/semihost_stat.h | 14 ++++
libgloss/riscv/semihost_syscall.h | 47 +++++++++++++
21 files changed, 692 insertions(+), 1 deletion(-)
create mode 100644 libgloss/riscv/semihost-sys_close.c
create mode 100644 libgloss/riscv/semihost-sys_exit.c
create mode 100644 libgloss/riscv/semihost-sys_fdtable.c
create mode 100644 libgloss/riscv/semihost-sys_fstat.c
create mode 100644 libgloss/riscv/semihost-sys_ftime.c
create mode 100644 libgloss/riscv/semihost-sys_isatty.c
create mode 100644 libgloss/riscv/semihost-sys_link.c
create mode 100644 libgloss/riscv/semihost-sys_lseek.c
create mode 100644 libgloss/riscv/semihost-sys_open.c
create mode 100644 libgloss/riscv/semihost-sys_read.c
create mode 100644 libgloss/riscv/semihost-sys_sbrk.c
create mode 100644 libgloss/riscv/semihost-sys_stat.c
create mode 100644 libgloss/riscv/semihost-sys_stat_common.c
create mode 100644 libgloss/riscv/semihost-sys_unlink.c
create mode 100644 libgloss/riscv/semihost-sys_write.c
create mode 100644 libgloss/riscv/semihost.specs
create mode 100644 libgloss/riscv/semihost_fdtable.h
create mode 100644 libgloss/riscv/semihost_stat.h
create mode 100644 libgloss/riscv/semihost_syscall.h
diff --git a/libgloss/riscv/Makefile.in b/libgloss/riscv/Makefile.in
index 579dd9554..185b6e6d2 100644
--- a/libgloss/riscv/Makefile.in
+++ b/libgloss/riscv/Makefile.in
@@ -40,8 +40,38 @@ gloss_srcs = \
sys_wait.c \
sys_write.c
+# libsemihost reuses some of the libgloss minimal implementations
+
+semihost_srcs = \
+ nanosleep.c \
+ sys_chdir.c \
+ sys_chmod.c \
+ sys_chown.c \
+ sys_execve.c \
+ sys_fork.c \
+ sys_getcwd.c \
+ sys_getpid.c \
+ sys_kill.c \
+ sys_utime.c \
+ sys_wait.c \
+ semihost-sys_close.c \
+ semihost-sys_exit.c \
+ semihost-sys_fdtable.c \
+ semihost-sys_fstat.c \
+ semihost-sys_ftime.c \
+ semihost-sys_isatty.c \
+ semihost-sys_link.c \
+ semihost-sys_lseek.c \
+ semihost-sys_open.c \
+ semihost-sys_read.c \
+ semihost-sys_sbrk.c \
+ semihost-sys_stat.c \
+ semihost-sys_stat_common.c \
+ semihost-sys_unlink.c \
+ semihost-sys_write.c
+
gloss_specs = \
- nano.specs sim.specs
+ nano.specs sim.specs semihost.specs
# Extra files
@@ -134,6 +164,17 @@ sim_objs += $(sim_c_objs)
deps += $(sim_c_deps)
junk += $(sim_c_deps) $(sim_c_objs)
+semihost_c_srcs = $(filter %.c, $(semihost_srcs))
+semihost_c_objs = $(patsubst %.c, semihost-%.o, $(notdir $(semihost_c_srcs)))
+semihost_c_deps = $(patsubst %.c, semihost-%.d, $(notdir $(semihost_c_srcs)))
+
+$(semihost_c_objs): semihost-%.o : %.c
+ $(COMPILE) -c -o $@ $<
+
+semihost_objs += $(semihost_c_objs)
+deps += $(semihost_c_deps)
+junk += $(semihost_c_deps) $(semihost_c_objs)
+
#-------------------------------------------------------------------------
# Build Object Files from Assembly Source
#-------------------------------------------------------------------------
@@ -159,6 +200,16 @@ sim_objs += $(sim_asm_objs)
deps += $(sim_asm_deps)
junk += $(sim_asm_deps) $(sim_asm_objs)
+semihost_asm_objs = $(patsubst %.S, semihost-%.o, $(notdir $(gloss_asm_srcs)))
+semihost_asm_deps = $(patsubst %.S, semihost-%.d, $(notdir $(gloss_asm_srcs)))
+
+$(semihost_asm_objs) : semihost-%.o : %.S
+ $(COMPILE) -c -DUSING_SEMIHOST_SPECS -o $@ $<
+
+semihost_objs += $(semihost_asm_objs)
+deps += $(semihost_asm_deps)
+junk += $(semihost_asm_deps) $(semihost_asm_objs)
+
#-------------------------------------------------------------------------
# Build libgloss.a
#-------------------------------------------------------------------------
@@ -187,6 +238,19 @@ junk += $(sim_lib)
install_libs += $(sim_lib)
+#-------------------------------------------------------------------------
+# Build libsemihost.a
+#-------------------------------------------------------------------------
+
+semihost_lib = libsemihost.a
+$(semihost_lib) : $(semihost_objs)
+ $(AR) rcv $@ $^
+ $(RANLIB) $@
+
+junk += $(semihost_lib)
+
+install_libs += $(semihost_lib)
+
#-------------------------------------------------------------------------
# Build crt0.o
#-------------------------------------------------------------------------
diff --git a/libgloss/riscv/machine/syscall.h b/libgloss/riscv/machine/syscall.h
index 5cd15b848..88b9fdfda 100644
--- a/libgloss/riscv/machine/syscall.h
+++ b/libgloss/riscv/machine/syscall.h
@@ -54,4 +54,29 @@
#define SYS_time 1062
#define SYS_getmainvars 2011
+/* Semihosting operations. */
+#define SEMIHOST_clock 0x10
+#define SEMIHOST_close 0x02
+#define SEMIHOST_elapsed 0x30
+#define SEMIHOST_errno 0x13
+#define SEMIHOST_exit 0x18
+#define SEMIHOST_exit_extended 0x20
+#define SEMIHOST_flen 0x0C
+#define SEMIHOST_get_cmdline 0x15
+#define SEMIHOST_heapinfo 0x16
+#define SEMIHOST_iserror 0x08
+#define SEMIHOST_istty 0x09
+#define SEMIHOST_open 0x01
+#define SEMIHOST_read 0x06
+#define SEMIHOST_readc 0x07
+#define SEMIHOST_remove 0x0E
+#define SEMIHOST_rename 0x0F
+#define SEMIHOST_seek 0x0A
+#define SEMIHOST_system 0x12
+#define SEMIHOST_tickfreq 0x31
+#define SEMIHOST_time 0x11
+#define SEMIHOST_tmpnam 0x0D
+#define SEMIHOST_write 0x05
+#define SEMIHOST_writec 0x03
+#define SEMIHOST_write0 0x04
#endif
diff --git a/libgloss/riscv/semihost-sys_close.c b/libgloss/riscv/semihost-sys_close.c
new file mode 100644
index 000000000..47402340c
--- /dev/null
+++ b/libgloss/riscv/semihost-sys_close.c
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2020 Embecosm Limited
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+#include <machine/syscall.h>
+#include "semihost_syscall.h"
+#include "semihost_fdtable.h"
+
+/* Close a file. */
+int
+_close (int file)
+{
+ long res;
+ struct fdentry *fd =__get_fdentry (file);
+ long data_block[1];
+
+ if (fd == NULL)
+ return -1;
+
+ data_block[0] = fd->handle;
+ res = syscall_errno (SEMIHOST_close, data_block);
+
+ if (res != 0)
+ return res;
+
+ __remove_fdentry (file);
+ return 0;
+}
diff --git a/libgloss/riscv/semihost-sys_exit.c b/libgloss/riscv/semihost-sys_exit.c
new file mode 100644
index 000000000..626fb6aeb
--- /dev/null
+++ b/libgloss/riscv/semihost-sys_exit.c
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2020 Embecosm Limited
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+#include <machine/syscall.h>
+#include "semihost_syscall.h"
+
+#define ADP_Stopped_ApplicationExit 0x20026
+
+/* Exit a program without cleaning up files. */
+void
+_exit (int exit_status)
+{
+#if __riscv_xlen == 32
+ syscall_errno (SEMIHOST_exit, (long *) ADP_Stopped_ApplicationExit);
+#else
+ /* The semihosting exit operation only allows 64-bit targets to report the
+ exit code. */
+ long data_block[] = {ADP_Stopped_ApplicationExit, exit_status};
+ syscall_errno (SEMIHOST_exit, data_block);
+#endif
+ while (1);
+}
diff --git a/libgloss/riscv/semihost-sys_fdtable.c b/libgloss/riscv/semihost-sys_fdtable.c
new file mode 100644
index 000000000..152c92d15
--- /dev/null
+++ b/libgloss/riscv/semihost-sys_fdtable.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2020 Embecosm Limited
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+#include "semihost_fdtable.h"
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#ifndef RISCV_MAX_OPEN_FILES
+#define RISCV_MAX_OPEN_FILES 16
+#endif
+
+extern int errno;
+extern int _open (const char *, int, ...);
+
+/* fdtable keeps track of the position of each file and is used to map stdin,
+ stdout and stderr to STDIN_FILENO, STDOUT_FILENO and STDERR_FILENO. */
+
+static struct fdentry fdtable[RISCV_MAX_OPEN_FILES];
+
+/* Initialize fdtable. A handle of -1 denotes an empty entry. */
+
+void __attribute__ ((constructor))
+init_semihosting ()
+{
+ int handle;
+
+ for (int i=0; i<RISCV_MAX_OPEN_FILES; i++)
+ fdtable[i].handle = -1;
+
+ /* Set up std streams. */
+ /* stdin. */
+ handle = _open (":tt", O_RDONLY);
+ fdtable[STDIN_FILENO].handle = handle;
+ fdtable[STDIN_FILENO].pos = 0;
+
+ /* stdout. */
+ handle = _open (":tt", O_WRONLY|O_CREAT|O_TRUNC);
+ fdtable[STDOUT_FILENO].handle = handle;
+ fdtable[STDOUT_FILENO].pos = 0;
+
+ /* stderr. */
+ handle = _open (":tt", O_WRONLY|O_CREAT|O_APPEND);
+ fdtable[STDERR_FILENO].handle = handle;
+ fdtable[STDERR_FILENO].pos = 0;
+}
+
+/* Add entry to fdtable. */
+
+int
+__add_fdentry (int handle)
+{
+ for (int i=0; i<RISCV_MAX_OPEN_FILES; i++)
+ if (fdtable[i].handle == -1)
+ {
+ fdtable[i].handle = handle;
+ fdtable[i].pos = 0;
+ return i;
+ }
+ /* Too many open files. */
+ errno = ENFILE;
+ return -1;
+}
+
+/* Return the fdentry for file or NULL if not found. */
+
+struct fdentry *
+__get_fdentry (int file)
+{
+ if (file<0 || file>=RISCV_MAX_OPEN_FILES || fdtable[file].handle == -1)
+ {
+ errno = EBADF;
+ return NULL;
+ }
+ return &fdtable[file];
+}
+
+/* Remove entry from fdtable. */
+
+void
+__remove_fdentry (int file)
+{
+ fdtable[file].handle = -1;
+}
diff --git a/libgloss/riscv/semihost-sys_fstat.c b/libgloss/riscv/semihost-sys_fstat.c
new file mode 100644
index 000000000..f57f0c07f
--- /dev/null
+++ b/libgloss/riscv/semihost-sys_fstat.c
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2020 Embecosm Limited
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+#include <string.h>
+#include <sys/stat.h>
+#include "semihost_stat.h"
+
+/* Status of an open file. The sys/stat.h header file required is
+ distributed in the include subdirectory for this C library. */
+
+int
+_fstat (int file, struct stat *st)
+{
+ /* Initialize st as not all fields will be set. */
+ memset (st, 0, sizeof (*st));
+
+ return __stat_common (file, st);
+}
diff --git a/libgloss/riscv/semihost-sys_ftime.c b/libgloss/riscv/semihost-sys_ftime.c
new file mode 100644
index 000000000..aeafc6ca2
--- /dev/null
+++ b/libgloss/riscv/semihost-sys_ftime.c
@@ -0,0 +1,16 @@
+/*
+ * Copyright (C) 2020 Embecosm Limited
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+#include <machine/syscall.h>
+#include <sys/timeb.h>
+#include "semihost_syscall.h"
+
+/* Get the current time. */
+int
+_ftime (struct timeb *tp)
+{
+ tp->time = syscall_errno (SEMIHOST_time, 0);
+ tp->millitm = 0;
+ return 0;
+}
diff --git a/libgloss/riscv/semihost-sys_isatty.c b/libgloss/riscv/semihost-sys_isatty.c
new file mode 100644
index 000000000..02d8e39cb
--- /dev/null
+++ b/libgloss/riscv/semihost-sys_isatty.c
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2020 Embecosm Limited
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+#include <machine/syscall.h>
+#include <sys/stat.h>
+#include "semihost_syscall.h"
+#include "semihost_fdtable.h"
+
+int
+_isatty (int file)
+{
+ struct fdentry *fd =__get_fdentry (file);
+ long data_block[1];
+
+ if (fd == NULL)
+ return -1;
+
+ data_block[0] = fd->handle;
+ return syscall_errno (SEMIHOST_istty, data_block);
+}
diff --git a/libgloss/riscv/semihost-sys_link.c b/libgloss/riscv/semihost-sys_link.c
new file mode 100644
index 000000000..717c5c81c
--- /dev/null
+++ b/libgloss/riscv/semihost-sys_link.c
@@ -0,0 +1,9 @@
+/*
+ * Copyright (C) 2020 Embecosm Limited
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+/* Establish a new name for an existing file. */
+int _link (const char *old_name, const char *new_name)
+{
+ return -1;
+}
diff --git a/libgloss/riscv/semihost-sys_lseek.c b/libgloss/riscv/semihost-sys_lseek.c
new file mode 100644
index 000000000..68fccf2ff
--- /dev/null
+++ b/libgloss/riscv/semihost-sys_lseek.c
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2020 Embecosm Limited
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+#include <machine/syscall.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include "semihost_syscall.h"
+#include "semihost_fdtable.h"
+
+extern int errno;
+
+/* Set position in a file. */
+off_t
+_lseek (int file, off_t offset, int dir)
+{
+ long data_block[2];
+ long flen;
+ long res;
+ struct fdentry *fd;
+ off_t abs_pos;
+
+ fd =__get_fdentry (file);
+ if (fd == NULL)
+ {
+ errno = EBADF;
+ return -1;
+ }
+
+ if (dir == SEEK_CUR && offset == 0)
+ return fd->pos;
+
+ data_block[0] = fd->handle;
+
+ switch (dir)
+ {
+ case SEEK_SET:
+ abs_pos = offset;
+ break;
+ case SEEK_CUR:
+ abs_pos = fd->pos + offset;
+ break;
+ case SEEK_END:
+ data_block[1] = 0;
+ flen = syscall_errno (SEMIHOST_flen, data_block);
+ if (flen == -1)
+ return -1;
+ abs_pos = flen + offset;
+ break;
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (abs_pos < 0)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+
+ data_block[1] = abs_pos;
+ res = syscall_errno (SEMIHOST_seek, data_block);
+ if (res == 0)
+ {
+ fd->pos = abs_pos;
+ return abs_pos;
+ }
+ return res;
+}
diff --git a/libgloss/riscv/semihost-sys_open.c b/libgloss/riscv/semihost-sys_open.c
new file mode 100644
index 000000000..22f1d8206
--- /dev/null
+++ b/libgloss/riscv/semihost-sys_open.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2020 Embecosm Limited
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+#include <machine/syscall.h>
+#include "semihost_syscall.h"
+#include "semihost_fdtable.h"
+#include <errno.h>
+#include <string.h>
+#include <fcntl.h>
+
+extern int errno;
+
+#define SEMIHOST_MODE_R 0
+#define SEMIHOST_MODE_RPLUS 2
+#define SEMIHOST_MODE_W 4
+#define SEMIHOST_MODE_WPLUS 6
+#define SEMIHOST_MODE_A 8
+#define SEMIHOST_MODE_APLUS 10
+
+/* Open a file. */
+int
+_open (const char *name, int flags, ...)
+{
+ int fh;
+ int mode;
+ long data_block[3];
+
+ /* Work out mode from flags. */
+ if ((flags & (O_RDONLY | O_WRONLY | O_RDWR)) == O_RDONLY)
+ mode = SEMIHOST_MODE_R;
+ else if ((flags & (O_WRONLY | O_CREAT | O_TRUNC))
+ == (O_WRONLY | O_CREAT | O_TRUNC))
+ mode = SEMIHOST_MODE_W;
+ else if ((flags & (O_WRONLY | O_CREAT | O_APPEND))
+ == (O_WRONLY | O_CREAT | O_APPEND))
+ mode = SEMIHOST_MODE_A;
+ else if ((flags & (O_RDWR | O_CREAT | O_TRUNC))
+ == (O_RDWR | O_CREAT | O_TRUNC))
+ mode = SEMIHOST_MODE_WPLUS;
+ else if ((flags & (O_RDWR | O_CREAT | O_APPEND))
+ == (O_RDWR | O_CREAT | O_APPEND))
+ mode = SEMIHOST_MODE_APLUS;
+ else if (flags & O_RDWR)
+ mode = SEMIHOST_MODE_RPLUS;
+ else
+ {
+ errno = EINVAL;
+ return -1;
+ }
+
+ data_block[0] = (long) name;
+ data_block[1] = mode;
+ data_block[2] = strlen (name);
+ fh = syscall_errno (SEMIHOST_open, data_block);
+ /* Failed to open file. */
+ if (fh == -1)
+ return -1;
+
+ /* Register the file in the fdtable. */
+ return __add_fdentry (fh);
+}
diff --git a/libgloss/riscv/semihost-sys_read.c b/libgloss/riscv/semihost-sys_read.c
new file mode 100644
index 000000000..3164eed56
--- /dev/null
+++ b/libgloss/riscv/semihost-sys_read.c
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2020 Embecosm Limited
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+#include <machine/syscall.h>
+#include <errno.h>
+#include <sys/types.h>
+#include "semihost_syscall.h"
+#include "semihost_fdtable.h"
+
+/* Read from a file. */
+ssize_t _read (int file, void *ptr, size_t len)
+{
+ struct fdentry *fd =__get_fdentry (file);
+ long data_block[3];
+ long res;
+
+ if (fd == NULL)
+ return -1;
+
+ data_block[0] = fd->handle;
+ data_block[1] = (long) ptr;
+ data_block[2] = len;
+ res = syscall_errno (SEMIHOST_read, data_block);
+ if (res >= 0)
+ {
+ ssize_t bytes_read = len - res;
+ fd->pos += bytes_read;
+ return bytes_read;
+ }
+ return -1;
+}
diff --git a/libgloss/riscv/semihost-sys_sbrk.c b/libgloss/riscv/semihost-sys_sbrk.c
new file mode 100644
index 000000000..cbd035832
--- /dev/null
+++ b/libgloss/riscv/semihost-sys_sbrk.c
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2020 Embecosm Limited
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+/* Semihosting requires that sbrk be implemented without a syscall. */
+extern char _end[]; /* _end is set in the linker command file. */
+char *heap_ptr;
+
+/*
+ * sbrk -- changes heap size size. Get nbytes more
+ * RAM. We just increment a pointer in what's
+ * left of memory on the board.
+ */
+char *
+_sbrk (nbytes)
+ int nbytes;
+{
+ char *base;
+
+ if (!heap_ptr)
+ heap_ptr = (char *)&_end;
+ base = heap_ptr;
+ heap_ptr += nbytes;
+
+ return base;
+}
diff --git a/libgloss/riscv/semihost-sys_stat.c b/libgloss/riscv/semihost-sys_stat.c
new file mode 100644
index 000000000..4015801b9
--- /dev/null
+++ b/libgloss/riscv/semihost-sys_stat.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2020 Embecosm Limited
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+#include <machine/syscall.h>
+#include <string.h>
+#include <fcntl.h>
+#include "semihost_stat.h"
+
+/* Status of a file (by name). */
+
+int
+_stat (const char *name, struct stat *st)
+{
+ int file;
+ int res;
+
+ /* Initialize st as not all fields will be set. */
+ memset (st, 0, sizeof (*st));
+
+ /* Try to open file. */
+ file = _open (name, O_RDONLY);
+ if (file == -1)
+ /* _open should have already set errno. */
+ return -1;
+
+ /* File opened successfully, infer read permission for owner and assume it is
+ a regular file. */
+ st->st_mode |= S_IREAD | S_IFREG;
+
+ /* Fill in more info. */
+ res = __stat_common (file, st);
+
+ _close (file);
+ return res;
+}
diff --git a/libgloss/riscv/semihost-sys_stat_common.c b/libgloss/riscv/semihost-sys_stat_common.c
new file mode 100644
index 000000000..b38eb0863
--- /dev/null
+++ b/libgloss/riscv/semihost-sys_stat_common.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2020 Embecosm Limited
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+#include <machine/syscall.h>
+#include "semihost_syscall.h"
+#include <sys/stat.h>
+#include "semihost_fdtable.h"
+
+/* Used by _fstat and _stat to fill in some common details. */
+
+int
+__stat_common (int file, struct stat *st)
+{
+ int flen;
+ struct fdentry *fd =__get_fdentry (file);
+ long data_block[1];
+
+ if (fd == NULL)
+ return -1;
+
+ data_block[0] = fd->handle;
+
+ /* Assume character device and default block size of 4096. */
+ st->st_mode |= S_IFCHR;
+ st->st_blksize = 4096;
+
+ /* Attempt to get length of file. */
+ flen = syscall_errno (SEMIHOST_flen, data_block);
+ if (flen == -1)
+ return -1;
+
+ st->st_size = flen;
+
+ return 0;
+}
diff --git a/libgloss/riscv/semihost-sys_unlink.c b/libgloss/riscv/semihost-sys_unlink.c
new file mode 100644
index 000000000..1d2a6a0f9
--- /dev/null
+++ b/libgloss/riscv/semihost-sys_unlink.c
@@ -0,0 +1,15 @@
+/*
+ * Copyright (C) 2020 Embecosm Limited
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+#include <machine/syscall.h>
+#include "semihost_syscall.h"
+#include <string.h>
+
+/* Remove a file's directory entry. */
+int
+_unlink (const char *name)
+{
+ long data_block[] = {(long) name, strlen (name)};
+ return syscall_errno (SEMIHOST_remove, data_block);
+}
diff --git a/libgloss/riscv/semihost-sys_write.c b/libgloss/riscv/semihost-sys_write.c
new file mode 100644
index 000000000..9aee6d30b
--- /dev/null
+++ b/libgloss/riscv/semihost-sys_write.c
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2020 Embecosm Limited
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+#include <machine/syscall.h>
+#include <sys/types.h>
+#include "semihost_syscall.h"
+#include "semihost_fdtable.h"
+
+/* Write to a file. */
+ssize_t
+_write (int file, const void *ptr, size_t len)
+{
+ struct fdentry *fd =__get_fdentry (file);
+ long data_block[3];
+ long res;
+
+ if (fd == NULL)
+ return -1;
+
+ data_block[0] = fd->handle;
+ data_block[1] = (long) ptr;
+ data_block[2] = len;
+ res = syscall_errno (SEMIHOST_write, data_block);
+ if (res >= 0)
+ {
+ ssize_t bytes_written = len - res;
+ fd->pos += bytes_written;
+ return bytes_written;
+ }
+ return -1;
+}
diff --git a/libgloss/riscv/semihost.specs b/libgloss/riscv/semihost.specs
new file mode 100644
index 000000000..1c86c67e4
--- /dev/null
+++ b/libgloss/riscv/semihost.specs
@@ -0,0 +1,10 @@
+# Spec file for semihosting syscalls.
+
+%rename lib semihost_lib
+%rename link semihost_link
+
+*lib:
+--start-group -lc -lsemihost --end-group
+
+*link:
+%(semihost_link) %:replace-outfile(-lgloss -lsemihost)
diff --git a/libgloss/riscv/semihost_fdtable.h b/libgloss/riscv/semihost_fdtable.h
new file mode 100644
index 000000000..f596a409a
--- /dev/null
+++ b/libgloss/riscv/semihost_fdtable.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2020 Embecosm Limited
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+#include <sys/types.h>
+
+#ifndef RISCV_SEMIHOST_FDTABLE_H
+#define RISCV_SEMIHOST_FDTABLE_H
+
+extern void __attribute__ ((constructor)) init_semihosting ();
+extern int __add_fdentry (int);
+extern struct fdentry * __get_fdentry (int);
+extern void __remove_fdentry (int);
+
+struct fdentry
+{
+ int handle;
+ off_t pos;
+};
+
+#endif
diff --git a/libgloss/riscv/semihost_stat.h b/libgloss/riscv/semihost_stat.h
new file mode 100644
index 000000000..c040fe8e7
--- /dev/null
+++ b/libgloss/riscv/semihost_stat.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright (C) 2020 Embecosm Limited
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+#include <sys/types.h>
+
+#ifndef RISCV_SEMIHOST_STAT_H
+#define RISCV_SEMIHOST_STAT_H
+
+extern int __stat_common (int, struct stat *);
+extern int _open (const char *, int, ...);
+extern int _close (int);
+
+#endif
diff --git a/libgloss/riscv/semihost_syscall.h b/libgloss/riscv/semihost_syscall.h
new file mode 100644
index 000000000..50e731b40
--- /dev/null
+++ b/libgloss/riscv/semihost_syscall.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2020 Embecosm Limited
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+#ifndef _INTERNAL_SYSCALL_H
+#define _INTERNAL_SYSCALL_H
+
+extern int errno;
+
+static inline long
+__semihost_syscall (long id, long *data_block)
+{
+ register long a0 asm ("a0") = id;
+ register long a1 asm ("a1") = (long) data_block;
+
+ /* RISC-V semihosting trap sequence. Must be uncompressed and must not
+ cross page boundary. */
+ asm volatile (
+ ".balign 16 \n"
+ ".option push \n"
+ ".option norvc \n"
+ "slli zero, zero, 0x1f \n"
+ "ebreak \n"
+ "srai zero, zero, 0x7 \n"
+ ".option pop \n"
+ : "+r"(a0) : "r"(a1) : "memory");
+
+ return a0;
+}
+
+static inline long
+__syscall_error ()
+{
+ errno = __semihost_syscall (SEMIHOST_errno, 0);
+ return -1;
+}
+
+static inline long
+syscall_errno (long id, long *data_block)
+{
+ long res = __semihost_syscall (id, data_block);
+ if (res < 0)
+ return __syscall_error ();
+ return res;
+}
+
+#endif
--
2.17.1
next prev parent reply other threads:[~2020-12-15 12:00 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 [this message]
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=aee4f08e-6209-c656-4546-f488aa48e96c@embecosm.com \
--to=craig.blackmore@embecosm.com \
--cc=kito.cheng@gmail.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).