From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [63.128.21.124]) by sourceware.org (Postfix) with ESMTP id 206093858D29 for ; Tue, 15 Dec 2020 22:52:11 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 206093858D29 Received: from mail-pl1-f199.google.com (mail-pl1-f199.google.com [209.85.214.199]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-248-Ph71GWX7NFWZIkv18gpq-A-1; Tue, 15 Dec 2020 17:52:08 -0500 X-MC-Unique: Ph71GWX7NFWZIkv18gpq-A-1 Received: by mail-pl1-f199.google.com with SMTP id 1so11334934plb.4 for ; Tue, 15 Dec 2020 14:52:08 -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=cfUKuYqjKM7iC8yHqpWkaOV6t0Pnfn7zK9ZDJu4ZuLg=; b=kihRosHiYPHI8QFFGXHoBy3p/xj510y9/2GED576OcFWxOaE9zck+yzVxP/bTuB3Iw TgFIsTsUkl5y4W2xjRBkYN8UfLgbglMI8FZm1hOvdniNTFPKp78dq0GlK7mynT5hfyPH OxdlzTiSeCrmttjOPQYE3BUgFg9uOAlKY4QpvRaaGGC3YeT/MlfaQ2Vt8QsayDaO4bkl CNq9godYKNRPfvBLj0QYH3tII5eC0VStQteZmg/fj2d8ZEoiHYBHsCQYFMopQz4Mk1aY a/YWLHrb+Wijsu3Y06nZBrJCHXf7+80WFbCX7i2dJGXFSwVOWWiMbvPbv5Ci8Hbk/uy9 kYaw== X-Gm-Message-State: AOAM531M5IB5qx7KTHEl8Kp6aJ3piVp5Jd5WSkMOPPNX3nZx+ROcxgcr 0FLWZWU/wBe8AApSy0EHoSrf7+Er3DcBot14JOdqGlLEEqbq+cyUiUgr+A86ZC1obTSAjCTg5A/ HyB45Dyxt0R8o9igQlLSWK2E/V+s5xko= X-Received: by 2002:a17:90a:5911:: with SMTP id k17mr719183pji.152.1608072726709; Tue, 15 Dec 2020 14:52:06 -0800 (PST) X-Google-Smtp-Source: ABdhPJyM0DJJ0W+sEeqtL+eEeHKfnaz8LMH1DBYCbmFMVIP9azebz98j1aUBteEQJmyrLwZHRBIDE/V59YUaD/xWIjE= X-Received: by 2002:a17:90a:5911:: with SMTP id k17mr719174pji.152.1608072726390; Tue, 15 Dec 2020 14:52:06 -0800 (PST) MIME-Version: 1.0 References: <694d497b-bc07-a3ba-2643-a7336927e9a7@embecosm.com> In-Reply-To: From: Jeff Johnston Date: Tue, 15 Dec 2020 17:51:55 -0500 Message-ID: Subject: Re: [PATCH] RISC-V: Add semihosting support To: Craig Blackmore Cc: Newlib X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-11.9 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, HTML_MESSAGE, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL, 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 Content-Type: text/plain; charset="UTF-8" X-Content-Filtered-By: Mailman/MimeDel 2.1.29 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: Tue, 15 Dec 2020 22:52:15 -0000 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. 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 > >> +#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 > +#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 > +#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 > +#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..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 > +#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..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 > +#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..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 > +#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..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 > +#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..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 > +#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..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 > +#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..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 > +#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..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 > +#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..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 > +#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..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 > +#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..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 > + > +#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 > + > +#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 > > >