From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-wr1-x442.google.com (mail-wr1-x442.google.com [IPv6:2a00:1450:4864:20::442]) by sourceware.org (Postfix) with ESMTPS id 2C0C0385701F for ; Mon, 30 Nov 2020 14:05:52 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 2C0C0385701F Received: by mail-wr1-x442.google.com with SMTP id u12so16416675wrt.0 for ; Mon, 30 Nov 2020 06:05:52 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to:cc; bh=pyeb98rJy4N6Tun1Fi94v/lWFeBZUJT/CSOPHMhSxCI=; b=grTikqnIAxxxj8xWivuX3UFsMiHJ2tfuE0o0+8HAPJn3ezWGETl8BJfsMTx48TY4d+ v6V+qT/n9LwkuL18MrX1IgxhR82x9LzhBqXi4TglAMguGDARGaqT1/u0nua0qOjVYRuf LOu2OwdF7CCcrb0dDDj+7f4V8SrtRe/uuoewK71vDmUwwftuAG50hijq+axaNdsmKO4/ OumPZppQBM5SRb/teudHjV4i9u2I6HdiLZLAE49FH1L/C9DfwhZEgIT1mlftwoiNUdE6 Yxi86eU20V+l7NZbSm3xMV/T+CeI2JpSCkaud5gJ5yf6boXSQl4f8jI9veYhZA3Tc+52 YbDA== X-Gm-Message-State: AOAM533Zk9W7X5YECuDMhj5c/ubjjPMxYy4FM0chWcOoIxvrmkZlNfEj tWpdqTWeQQGRcZwORGS+2P4jHVE5uhfIYxtJdm3vWVncbS7T/w== X-Google-Smtp-Source: ABdhPJzfLQW0k2ux2Rqyvcf6sEv4nrlifFZs/pyX8dV4aucAITB/nhzfYsQWCJNCaNDAcQQWIsBDL4xv2U+SdYFfsS0= X-Received: by 2002:adf:fd52:: with SMTP id h18mr28208627wrs.90.1606745150783; Mon, 30 Nov 2020 06:05:50 -0800 (PST) MIME-Version: 1.0 References: <694d497b-bc07-a3ba-2643-a7336927e9a7@embecosm.com> In-Reply-To: <694d497b-bc07-a3ba-2643-a7336927e9a7@embecosm.com> From: Kito Cheng Date: Mon, 30 Nov 2020 22:05:39 +0800 Message-ID: Subject: Re: [PATCH] RISC-V: Add semihosting support To: Craig Blackmore Cc: Newlib , Keith Packard Content-Type: text/plain; charset="UTF-8" X-Spam-Status: No, score=-7.3 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, KAM_ASCII_DIVIDERS, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: newlib@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Newlib mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 30 Nov 2020 14:05:55 -0000 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 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 > +#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 > +#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 > +#include > +#include > + > +#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 + 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 + 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 > +#include > +#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 > +#include > +#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 > +#include > +#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 > +#include > +#include > +#include > +#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 > +#include "semihost_syscall.h" > +#include "semihost_fdtable.h" > +#include > +#include > +#include > + > +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 > +#include > +#include > +#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 > +#include > +#include > +#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 > +#include "semihost_syscall.h" > +#include > +#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 > +#include "semihost_syscall.h" > +#include > + > +/* 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 > +#include > +#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 > + > +#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 > + > +#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 > >