From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-wr1-x42a.google.com (mail-wr1-x42a.google.com [IPv6:2a00:1450:4864:20::42a]) by sourceware.org (Postfix) with ESMTPS id B0DCE383E82A for ; Mon, 30 Nov 2020 11:36:50 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org B0DCE383E82A Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=embecosm.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=craig.blackmore@embecosm.com Received: by mail-wr1-x42a.google.com with SMTP id k14so15750767wrn.1 for ; Mon, 30 Nov 2020 03:36:50 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=embecosm.com; s=google; h=to:from:subject:autocrypt:message-id:date:user-agent:mime-version :content-language; bh=58LD2dAJMf6mrFomxGsY5rjoGoopIYQ19W8w5mwSwA4=; b=TQFRdEsvW5zeznbw2FIvatogD8EmXJZsthGsx34IcjT4W8SzOGMgErxuxJHz8S8rAW VNSC6ga7bmikiq01n+nlbsetXlxbPYpTHHlMb5UQ/LGqYWaZya9G0HOBn4a9aHyUW+u/ gSyuGy+x1ALVKL5cKkm8EdXxYcQYG3XGpQ3EnlxT2bYcA2VkfXalnoQUyBF4+5EGCRvE mtS3jC/8da33wg0niw+QMdoZNLWXPLmeLcvgYFwHSSEBQDcK38MFjM7awHhxYk8DMQhD FenuRq6knJosACtCygvWx2pcSI0HiDCHWgossCXXd4+1JYC04y0jLHAp/6ESvIP4la6K YLzQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:to:from:subject:autocrypt:message-id:date :user-agent:mime-version:content-language; bh=58LD2dAJMf6mrFomxGsY5rjoGoopIYQ19W8w5mwSwA4=; b=fYU5Jy1wM8dq3RNT1qIjYC849GCkaxMBD4Gw+iCpdyoWxVxmCSUmPHWPiHL0KMfkE0 dQRCfA9N6steSc7Q8urPZ3IiCHyyYm5klesQ0i3+RFmdIhMyEErt3wFxXNtivkxjJYbO cGinQKpLJ63a9JWuOJCcrcPeB2x/EQWl/ZZ1mzcW/GKMIrOAmmcddlQghbsHQM0iFi+T Jh1HkVkuTeTCVOUw8IvWL3OL2GCUcepKujzzUV2i+VA0AlXUpbrixOxGSf3O8AzlQigw za1gWfOuMX/8YeOg6MkC0sNo1nx7AMEXD/J85HYwMUhhGsQXuShSNH4QWYnYwJw6o/Rw cRrw== X-Gm-Message-State: AOAM530SiYYCUJJ3Ckl85keAjDzS+9CCl6ExwWJbmQbHb6oF/sBenAkx VcFqd8y4KmOXp8GtqTkLW9yPMuZPIxb1N0XW X-Google-Smtp-Source: ABdhPJxsMF7odAnZaqhOnlbEiet2ZglP4pPqCPeNq/ZbLhJvhYWXGcIyLH3a5EXSVrUGgK1Aw+D8eA== X-Received: by 2002:a5d:414e:: with SMTP id c14mr28147316wrq.256.1606736209060; Mon, 30 Nov 2020 03:36:49 -0800 (PST) Received: from [192.168.43.61] ([85.255.237.170]) by smtp.gmail.com with ESMTPSA id j4sm27150373wrn.83.2020.11.30.03.36.48 for (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Mon, 30 Nov 2020 03:36:48 -0800 (PST) To: newlib@sourceware.org From: Craig Blackmore Subject: [PATCH] RISC-V: Add semihosting support Autocrypt: addr=craig.blackmore@embecosm.com; prefer-encrypt=mutual; keydata= xsBNBFdIF8oBCACwrsvc6YVfzJRT+ZoBfL9jEb8ITwNahDxCGSG6sIWrJ9UFeTwE8fnNhMpz RyFRm0OXruS5k/8YHJHrxKxFY9cgZ3CWNftXEjRqURUWGtN/ESiw0J7nVfhSGQTo3LBzpXZ1 0JHk4ZHKDJKYa+fhybCHOs19BfP3HydHoTlc5QTKMfom0X/xo7WDdwUYeZsjD9u8IzHk7gNw 05Abk1vqni+J7Fghjp4RI8W3IsjpKOfV3f02OyO/MTSraXNyejO4JRl0A8b3q1Lq+G6Z7o5n LVief5JpkRyzWQSawTIBKmRZa9EzAKZXd6IJdY/sZt7pTir5EP7MHq4a+AtKfKuDkrDDABEB AAHNLkNyYWlnIEJsYWNrbW9yZSA8Y3JhaWcuYmxhY2ttb3JlQGVtYmVjb3NtLmNvbT7CwHgE EwECACIFAldIF8oCGwMGCwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEGEeRQLLl5WtydMH /1nYd9jmOBaF8w5gGgjF5eOO5b/cdUegmO///VYj/5R7iF/zbB6KgF0Obo5h2gG9AIfsZG+T ybuTx7oU1DZYEIndw+YP9c9Yi5de5UzEHwbJiV57W0n+MP0Widgw7p6XJmUQ1XbHxdcWp7nY EJa8ASKLuuIhO8JFUXbQ8BcUiWbsA/JxgCzeid8iixGrzPWj6iFzoK2mX4GqP+24pXSDUamM TXmSQd2taYEsyUdJNiEkUC51ncRcMuThjdtfn6Ok+7lHjh3Zz8q0keJz5pnIp4EXdkAgKSjq U42PMrd3v1HoIFINTtr5F23OdkxoQzysu4GMO4pkw5pwz95Uckr08ojOwE0EV0gXygEIAKv/ luYHmCG/qefgzdbnegwMdG5753NJ+zGxFltFX6aaOPZ8go9Omf6zwjybUKv6Qx6AlDanwCl3 ewVQs+h9iW8uaQBRgeDmwAGMG/doBiFqs7X0jBf23exMiJezXlKb2ZlKzMAbzJ87408AzRaV sZdwEpXHVi2mRPoXtMrqL5iQEyG5hdx2ySj5164DIgVOs/ypFiaiFaDPkIcAQTzJrxsbt6pf iI9kT93DO9nRKVV0pPWztV8P5gKM8HY2rS0wQcfrqAU6T89Aa0VFw92J+w5d2spF8MUNPsvR NLm9ooCF3YME9STYHXrNH1U9fJUWpIC+b49UoWSWRD9nwl2h2i8AEQEAAcLAXwQYAQIACQUC V0gXygIbDAAKCRBhHkUCy5eVreLbB/sHPs1xu78uNV8O4UPTX7D5zBBS3nsrbDr+8stmXRap xbvo6kqKzIMAXuO3bYB/NyJ/tFzuFr9Tjd/2g56D2186bp01/kgxJ9CEl/m2T3lG3DlxIoLg pCExzTLTb8zH/7/6mdeJ17cdnrK+2QAKYctReVPAC67cq5KmUyU3bv5e1JzhV4ezz/i/O+Jv el112ZEsa54ya9KZOUHbgAR6hLnRWIa+8yQTtXqYRc3LxLRfS80Wn0Err1YvqFYzJsQMC8ND xAeEuqQ1gfk1b0jmv7tYljNqsHqzGVbuWz6hyzyLv5GjcdSDKpbw/797gRKQSY8Gty5ynfUH O4kKyuZPrE8P Message-ID: <694d497b-bc07-a3ba-2643-a7336927e9a7@embecosm.com> Date: Mon, 30 Nov 2020 11:36:47 +0000 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Thunderbird/68.10.0 MIME-Version: 1.0 Content-Language: en-US X-Spam-Status: No, score=-13.3 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, HTML_MESSAGE, 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 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable 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: Mon, 30 Nov 2020 11:36:55 -0000 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 =3D \ sys_wait.c \ sys_write.c=20 =20 +# libsemihost reuses some of the libgloss minimal implementations + +semihost_srcs =3D \ + 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 =3D \ - nano.specs sim.specs + nano.specs sim.specs semihost.specs =20 # Extra files =20 @@ -134,6 +164,17 @@ sim_objs +=3D $(sim_c_objs) deps +=3D $(sim_c_deps) junk +=3D $(sim_c_deps) $(sim_c_objs) =20 +semihost_c_srcs =3D $(filter %.c, $(semihost_srcs)) +semihost_c_objs =3D $(patsubst %.c, semihost-%.o, $(notdir $(semihost_c_= srcs))) +semihost_c_deps =3D $(patsubst %.c, semihost-%.d, $(notdir $(semihost_c_= srcs))) + +$(semihost_c_objs): semihost-%.o : %.c + $(COMPILE) -c -o $@ $< + +semihost_objs +=3D $(semihost_c_objs) +deps +=3D $(semihost_c_deps) +junk +=3D $(semihost_c_deps) $(semihost_c_objs) + #-----------------------------------------------------------------------= -- # Build Object Files from Assembly Source #-----------------------------------------------------------------------= -- @@ -159,6 +200,16 @@ sim_objs +=3D $(sim_asm_objs) deps +=3D $(sim_asm_deps) junk +=3D $(sim_asm_deps) $(sim_asm_objs) =20 +semihost_asm_objs =3D $(patsubst %.S, semihost-%.o, $(notdir $(gloss_asm= _srcs))) +semihost_asm_deps =3D $(patsubst %.S, semihost-%.d, $(notdir $(gloss_asm= _srcs))) + +$(semihost_asm_objs) : semihost-%.o : %.S + $(COMPILE) -c -DUSING_SEMIHOST_SPECS -o $@ $< + +semihost_objs +=3D $(semihost_asm_objs) +deps +=3D $(semihost_asm_deps) +junk +=3D $(semihost_asm_deps) $(semihost_asm_objs) + #-----------------------------------------------------------------------= -- # Build libgloss.a #-----------------------------------------------------------------------= -- @@ -187,6 +238,19 @@ junk +=3D $(sim_lib) =20 install_libs +=3D $(sim_lib) =20 +#-----------------------------------------------------------------------= -- +# Build libsemihost.a +#-----------------------------------------------------------------------= -- + +semihost_lib =3D libsemihost.a +$(semihost_lib) : $(semihost_objs) + $(AR) rcv $@ $^ + $(RANLIB) $@ + +junk +=3D $(semihost_lib) + +install_libs +=3D $(semihost_lib) + #-----------------------------------------------------------------------= -- # Build crt0.o #-----------------------------------------------------------------------= -- diff --git a/libgloss/riscv/machine/syscall.h b/libgloss/riscv/machine/sy= scall.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 =20 +/* 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/semihos= t-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 =3D__get_fdentry (file); + long data_block[1]; + + if (fd =3D=3D NULL) + return -1; + + data_block[0] =3D fd->handle; + res =3D syscall_errno (SEMIHOST_close, data_block); + + if (res !=3D 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 =3D=3D 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[] =3D {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/semih= ost-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 s= tdin, + 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=3D0; iRISCV_MAX_OPEN_FILES || fdtable[file].handle =3D=3D= -1) + { + errno =3D EBADF; + return NULL; + } + return &fdtable[file]; +} + +/* Remove entry from fdtable. */ + +void +__remove_fdentry (int file) +{ + fdtable[file].handle =3D -1; +} diff --git a/libgloss/riscv/semihost-sys_fstat.c b/libgloss/riscv/semihos= t-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/semihos= t-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 =3D syscall_errno (SEMIHOST_time, 0); + tp->millitm =3D 0; + return 0; +} diff --git a/libgloss/riscv/semihost-sys_isatty.c b/libgloss/riscv/semiho= st-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 =3D__get_fdentry (file); + long data_block[1]; + + if (fd =3D=3D NULL) + return -1; + + data_block[0] =3D 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/semihos= t-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 =3D__get_fdentry (file); + if (fd =3D=3D NULL) + { + errno =3D EBADF; + return -1; + } + + if (dir =3D=3D SEEK_CUR && offset =3D=3D 0) + return fd->pos; + + data_block[0] =3D fd->handle; + + switch (dir) + { + case SEEK_SET: + abs_pos =3D offset; + break; + case SEEK_CUR: + abs_pos =3D fd->pos + offset; + break; + case SEEK_END: + data_block[1] =3D 0; + flen =3D syscall_errno (SEMIHOST_flen, data_block); + if (flen =3D=3D -1) + return -1; + abs_pos =3D flen + offset; + break; + default: + errno =3D EINVAL; + return -1; + } + + if (abs_pos < 0) + { + errno =3D EINVAL; + return -1; + } + + data_block[1] =3D abs_pos; + res =3D syscall_errno (SEMIHOST_seek, data_block); + if (res =3D=3D 0) + { + fd->pos =3D 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)) =3D=3D O_RDONLY) + mode =3D SEMIHOST_MODE_R; + else if ((flags & (O_WRONLY | O_CREAT | O_TRUNC)) + =3D=3D (O_WRONLY | O_CREAT | O_TRUNC)) + mode =3D SEMIHOST_MODE_W; + else if ((flags & (O_WRONLY | O_CREAT | O_APPEND)) + =3D=3D (O_WRONLY | O_CREAT | O_APPEND)) + mode =3D SEMIHOST_MODE_A; + else if ((flags & (O_RDWR | O_CREAT | O_TRUNC)) + =3D=3D (O_RDWR | O_CREAT | O_TRUNC)) + mode =3D SEMIHOST_MODE_WPLUS; + else if ((flags & (O_RDWR | O_CREAT | O_APPEND)) + =3D=3D (O_RDWR | O_CREAT | O_APPEND)) + mode =3D SEMIHOST_MODE_APLUS; + else if (flags & O_RDWR) + mode =3D SEMIHOST_MODE_RPLUS; + else + { + errno =3D EINVAL; + return -1; + } + + data_block[0] =3D (long) name; + data_block[1] =3D mode; + data_block[2] =3D strlen (name); + fh =3D syscall_errno (SEMIHOST_open, data_block); + /* Failed to open file. */ + if (fh =3D=3D -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 =3D__get_fdentry (file); + long data_block[3]; + long res; + + if (fd =3D=3D NULL) + return -1; + + data_block[0] =3D fd->handle; + data_block[1] =3D (long) ptr; + data_block[2] =3D len; + res =3D syscall_errno (SEMIHOST_read, data_block); + if (res >=3D 0) + { + ssize_t bytes_read =3D len - res; + fd->pos +=3D 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 f= ile. */ +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 =3D (char *)&_end; + base =3D heap_ptr; + heap_ptr +=3D 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 =3D _open (name, O_RDONLY); + if (file =3D=3D -1) + /* _open should have already set errno. */ + return -1; + + /* File opened successfully, infer read permission for owner and assum= e it is + a regular file. */ + st->st_mode |=3D S_IREAD | S_IFREG; + + /* Fill in more info. */ + res =3D __stat_common (file, st); + + _close (file); + return res; +} diff --git a/libgloss/riscv/semihost-sys_stat_common.c b/libgloss/riscv/s= emihost-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 =3D__get_fdentry (file); + long data_block[1]; + + if (fd =3D=3D NULL) + return -1; + + data_block[0] =3D fd->handle; + + /* Assume character device and default block size of 4096. */ + st->st_mode |=3D S_IFCHR; + st->st_blksize =3D 4096; + + /* Attempt to get length of file. */ + flen =3D syscall_errno (SEMIHOST_flen, data_block); + if (flen =3D=3D -1) + return -1; + + st->st_size =3D flen; + + return 0; +} diff --git a/libgloss/riscv/semihost-sys_unlink.c b/libgloss/riscv/semiho= st-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[] =3D {(long) name, strlen (name)}; + return syscall_errno (SEMIHOST_remove, data_block); +} diff --git a/libgloss/riscv/semihost-sys_write.c b/libgloss/riscv/semihos= t-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 =3D__get_fdentry (file); + long data_block[3]; + long res; + + if (fd =3D=3D NULL) + return -1; + + data_block[0] =3D fd->handle; + data_block[1] =3D (long) ptr; + data_block[2] =3D len; + res =3D syscall_errno (SEMIHOST_write, data_block); + if (res >=3D 0) + { + ssize_t bytes_written =3D len - res; + fd->pos +=3D bytes_written; + return bytes_written; + } + return -1; +} diff --git a/libgloss/riscv/semihost.specs b/libgloss/riscv/semihost.spec= s 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_sta= t.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") =3D id; + register long a1 asm ("a1") =3D (long) data_block; + + /* RISC-V semihosting trap sequence. Must be uncompressed and must no= t + 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 =3D __semihost_syscall (SEMIHOST_errno, 0); + return -1; +} + +static inline long +syscall_errno (long id, long *data_block) +{ + long res =3D __semihost_syscall (id, data_block); + if (res < 0) + return __syscall_error (); + return res; +} + +#endif --=20 2.17.1