From 6d5331054ee3c957a4d3c8df05321f670c962020 Mon Sep 17 00:00:00 2001 From: Vladimir Isaev Date: Tue, 21 May 2024 10:56:49 +0100 Subject: [PATCH] arc: libgloss: Introduce hostlink interface There is a special interface built in ARC simulators (such as nSIM) called MetaWare hostlink IO which can be used to implement system calls. This commit adds support for this interface to the ARC port of libgloss. Here is an example of using this interface: $ arc-elf32-gcc -mcpu=hs -specs=hl.specs main.c -o main $ nsimdrv -tcf $NSIM_HOME/etc/tcf/templates/hs48_full.tcf main Hello, World! Signed-off-by: Vladimir Isaev --- libgloss/arc/arc-main-helper.c | 73 +++++++ libgloss/arc/arc-timer.c | 129 +++++++++++ libgloss/arc/arc-timer.h | 25 +++ libgloss/arc/crt0.S | 26 ++- libgloss/arc/hl-setup.c | 27 +++ libgloss/arc/hl-stub.c | 81 +++++++ libgloss/arc/hl.specs | 14 ++ libgloss/arc/hl/hl_api.c | 350 ++++++++++++++++++++++++++++++ libgloss/arc/hl/hl_api.h | 77 +++++++ libgloss/arc/hl/hl_argc.c | 45 ++++ libgloss/arc/hl/hl_argv.c | 67 ++++++ libgloss/arc/hl/hl_clock.c | 87 ++++++++ libgloss/arc/hl/hl_close.c | 58 +++++ libgloss/arc/hl/hl_exit.c | 42 ++++ libgloss/arc/hl/hl_fstat.c | 95 ++++++++ libgloss/arc/hl/hl_gettimeofday.c | 69 ++++++ libgloss/arc/hl/hl_gw.c | 180 +++++++++++++++ libgloss/arc/hl/hl_gw.h | 46 ++++ libgloss/arc/hl/hl_isatty.c | 64 ++++++ libgloss/arc/hl/hl_lseek.c | 68 ++++++ libgloss/arc/hl/hl_open.c | 89 ++++++++ libgloss/arc/hl/hl_read.c | 105 +++++++++ libgloss/arc/hl/hl_toolchain.h | 53 +++++ libgloss/arc/hl/hl_unlink.c | 59 +++++ libgloss/arc/hl/hl_write.c | 97 +++++++++ libgloss/arc/libcfunc.c | 6 +- libgloss/arc/readme-hostlink.md | 90 ++++++++ 27 files changed, 2111 insertions(+), 11 deletions(-) create mode 100644 libgloss/arc/arc-main-helper.c create mode 100644 libgloss/arc/arc-timer.c create mode 100644 libgloss/arc/arc-timer.h create mode 100644 libgloss/arc/hl-setup.c create mode 100644 libgloss/arc/hl-stub.c create mode 100644 libgloss/arc/hl.specs create mode 100644 libgloss/arc/hl/hl_api.c create mode 100644 libgloss/arc/hl/hl_api.h create mode 100644 libgloss/arc/hl/hl_argc.c create mode 100644 libgloss/arc/hl/hl_argv.c create mode 100644 libgloss/arc/hl/hl_clock.c create mode 100644 libgloss/arc/hl/hl_close.c create mode 100644 libgloss/arc/hl/hl_exit.c create mode 100644 libgloss/arc/hl/hl_fstat.c create mode 100644 libgloss/arc/hl/hl_gettimeofday.c create mode 100644 libgloss/arc/hl/hl_gw.c create mode 100644 libgloss/arc/hl/hl_gw.h create mode 100644 libgloss/arc/hl/hl_isatty.c create mode 100644 libgloss/arc/hl/hl_lseek.c create mode 100644 libgloss/arc/hl/hl_open.c create mode 100644 libgloss/arc/hl/hl_read.c create mode 100644 libgloss/arc/hl/hl_toolchain.h create mode 100644 libgloss/arc/hl/hl_unlink.c create mode 100644 libgloss/arc/hl/hl_write.c create mode 100644 libgloss/arc/readme-hostlink.md diff --git a/libgloss/arc/arc-main-helper.c b/libgloss/arc/arc-main-helper.c new file mode 100644 index 000000000..e27e15b34 --- /dev/null +++ b/libgloss/arc/arc-main-helper.c @@ -0,0 +1,73 @@ +/* + * arc-main-helper.c -- provide custom __setup_argv_and_call_main(); + * This function uses _argc(), _argvlen(), _argv() and _setup_low_level(). + * Description for these functions can be found below in this file. + * + * Copyright (c) 2024 Synopsys Inc. + * + * The authors hereby grant permission to use, copy, modify, distribute, + * and license this software and its documentation for any purpose, provided + * that existing copyright notices are retained in all copies and that this + * notice is included verbatim in any distributions. No written agreement, + * license, or royalty fee is required for any of the authorized uses. + * Modifications to this software may be copyrighted by their authors + * and need not follow the licensing terms described here, provided that + * the new terms are clearly indicated on the first page of each file where + * they apply. + * + */ + +#include +#include +#include + +/* Return number of arguments passed to host executable. */ +extern int _argc (void); +/* + * Return buffer length to be used for a given argument number. + * Buffer length includes '\0' character. + */ +extern uint32_t _argvlen (int a); +/* + * Copy argument into buffer arg. + * arg must be no less than argvlen(a) length. + */ +extern int _argv (int a, char *arg); +/* Custom setup. Can be used to setup some port-specific stuff. */ +extern int _setup_low_level (void); +/* main function to call. */ +extern int main (int argc, char **argv); + +/* Copy arguments from host to local stack and call main. */ +int +__setup_argv_and_call_main (void) +{ + int i; + int argc; + char **argv = NULL; + + argc = _argc (); + if (argc > 0) + argv = alloca ((argc + 1) * sizeof (char *)); + + for (i = 0; i < argc; i++) + { + uint32_t arg_len; + + arg_len = _argvlen (i); + if (arg_len == 0) + break; + + argv[i] = alloca (arg_len); + + if (_argv (i, argv[i]) < 0) + break; + } + + if (argv) + argv[i] = NULL; + + _setup_low_level (); + + return main (i, argv); +} diff --git a/libgloss/arc/arc-timer.c b/libgloss/arc/arc-timer.c new file mode 100644 index 000000000..2437407e7 --- /dev/null +++ b/libgloss/arc/arc-timer.c @@ -0,0 +1,129 @@ +/* + * arc-timer.c -- provide API for ARC timers. + * + * Copyright (c) 2024 Synopsys Inc. + * + * The authors hereby grant permission to use, copy, modify, distribute, + * and license this software and its documentation for any purpose, provided + * that existing copyright notices are retained in all copies and that this + * notice is included verbatim in any distributions. No written agreement, + * license, or royalty fee is required for any of the authorized uses. + * Modifications to this software may be copyrighted by their authors + * and need not follow the licensing terms described here, provided that + * the new terms are clearly indicated on the first page of each file where + * they apply. + * + */ + +#define ARC_TIM_BUILD 0x75 +#define ARC_TIM_BUILD_VER_MASK 0x00FF +#define ARC_TIM_BUILD_TIM0_FL 0x0100 +#define ARC_TIM_BUILD_TIM1_FL 0x0200 + +#define ARC_TIM_COUNT0 0x21 +#define ARC_TIM_CONTROL0 0x22 +#define ARC_TIM_LIMIT0 0x23 + +#define ARC_TIM_COUNT1 0x100 +#define ARC_TIM_CONTROL1 0x101 +#define ARC_TIM_LIMIT1 0x102 + +#define ARC_TIM_CONTROL_NH_FL 0x0002 + +/* Timer used by '_default' functions. */ +const unsigned int arc_timer_default = 0; + +/* Check if given timer exists. */ +static int +_arc_timer_present (unsigned int tim) +{ + unsigned int bcr = __builtin_arc_lr (ARC_TIM_BUILD); + unsigned int ver = bcr & ARC_TIM_BUILD_VER_MASK; + + if (ver == 0) + return 0; + else if (ver == 1) + return 1; + else if (tim == 0) + return ((bcr & ARC_TIM_BUILD_TIM0_FL) != 0); + else if (tim == 1) + return ((bcr & ARC_TIM_BUILD_TIM1_FL) != 0); + else + return 0; +} + +/* Get raw value of a given timer. */ +static unsigned int +_arc_timer_read (unsigned int tim) +{ + if (_arc_timer_present (tim)) + { + if (tim == 0) + return __builtin_arc_lr (ARC_TIM_COUNT0); + else if (tim == 1) + return __builtin_arc_lr (ARC_TIM_COUNT1); + } + + return 0; +} + +/* + * Set default values to a given timer. + * Defaults: Not Halted bit is set, limit is 0xFFFFFFFF, count set to 0. + */ +static void +_arc_timer_reset (unsigned int tim) +{ + unsigned int ctrl, tim_control, tim_count, tim_limit; + + if (_arc_timer_present (tim)) + { + if (tim == 0) + { + tim_control = ARC_TIM_CONTROL0; + tim_count = ARC_TIM_COUNT0; + tim_limit = ARC_TIM_LIMIT0; + } + else if (tim == 1) + { + tim_control = ARC_TIM_CONTROL1; + tim_count = ARC_TIM_COUNT1; + tim_limit = ARC_TIM_LIMIT1; + } + else + { + return; + } + + ctrl = __builtin_arc_lr (tim_control); + /* Disable timer interrupt when programming. */ + __builtin_arc_sr (0, tim_control); + /* Default limit is 24-bit, increase it to 32-bit. */ + __builtin_arc_sr (0xFFFFFFFF, tim_limit); + /* Set NH bit to count only when processor is running. */ + __builtin_arc_sr (ctrl | ARC_TIM_CONTROL_NH_FL, tim_control); + __builtin_arc_sr (0, tim_count); + } +} + + +/* Check if arc_timer_default exists. */ +int +_arc_timer_default_present (void) +{ + return _arc_timer_present (arc_timer_default); +} + +/* Read arc_timer_default value. */ +unsigned int +_arc_timer_default_read (void) +{ + return _arc_timer_read (arc_timer_default); +} + +/* Reset arc_timer_default. */ +void +_arc_timer_default_reset (void) +{ + _arc_timer_reset (arc_timer_default); +} diff --git a/libgloss/arc/arc-timer.h b/libgloss/arc/arc-timer.h new file mode 100644 index 000000000..cb573408b --- /dev/null +++ b/libgloss/arc/arc-timer.h @@ -0,0 +1,25 @@ +/* + * arc-timer.h -- provide API for the default (number 0) ARC timer. + * + * Copyright (c) 2024 Synopsys Inc. + * + * The authors hereby grant permission to use, copy, modify, distribute, + * and license this software and its documentation for any purpose, provided + * that existing copyright notices are retained in all copies and that this + * notice is included verbatim in any distributions. No written agreement, + * license, or royalty fee is required for any of the authorized uses. + * Modifications to this software may be copyrighted by their authors + * and need not follow the licensing terms described here, provided that + * the new terms are clearly indicated on the first page of each file where + * they apply. + * + */ + +#ifndef _ARC_TIMER_H +#define _ARC_TIMER_H + +void _arc_timer_default_reset (void); +int _arc_timer_default_present (void); +unsigned int _arc_timer_default_read (void); + +#endif /* !_ARC_TIMER_H */ diff --git a/libgloss/arc/crt0.S b/libgloss/arc/crt0.S index 6c24e8dcb..235f81028 100644 --- a/libgloss/arc/crt0.S +++ b/libgloss/arc/crt0.S @@ -206,16 +206,9 @@ __start: jl @_monstartup #endif /* PROFILE_SUPPORT */ - mov_s r0, r13 - mov_s r1, r14 ; branch to main -#if defined (__ARCEM__) || defined (__ARCHS__) mov fp,0 ; initialize frame pointer - jl @main -#else - bl.d @main - mov fp, 0 ; initialize frame pointer -#endif /* __ARCEM__ || __ARCHS__ */ + jl @__setup_argv_and_call_main #ifdef PROFILE_SUPPORT mov r13, r0 ; Save return code @@ -225,6 +218,23 @@ __start: ; r0 contains exit code j @exit + .size __start, .-__start + +;;; arc-main-helper.o object can be used to replace this function and +;;; properly set up arguments and/or other low-level stuff. + .section .text.__setup_argv_and_call_main,"ax",@progbits + .weak __setup_argv_and_call_main + .type __setup_argv_and_call_main, @function + .align 4 + +__setup_argv_and_call_main: + push_s blink +; Call main with argc = 0 and *argv[] = 0 + mov r0, 0 + mov r1, 0 + jl @main + pop_s blink + j_s [blink] .section .text._exit_halt,"ax",@progbits .global _exit_halt diff --git a/libgloss/arc/hl-setup.c b/libgloss/arc/hl-setup.c new file mode 100644 index 000000000..a8affbc8d --- /dev/null +++ b/libgloss/arc/hl-setup.c @@ -0,0 +1,27 @@ +/* + * hl-setup.c -- provide _setup_low_level() to initialize timer. + * + * Copyright (c) 2024 Synopsys Inc. + * + * The authors hereby grant permission to use, copy, modify, distribute, + * and license this software and its documentation for any purpose, provided + * that existing copyright notices are retained in all copies and that this + * notice is included verbatim in any distributions. No written agreement, + * license, or royalty fee is required for any of the authorized uses. + * Modifications to this software may be copyrighted by their authors + * and need not follow the licensing terms described here, provided that + * the new terms are clearly indicated on the first page of each file where + * they apply. + * + */ + +#include "arc-timer.h" + +/* Configure and reset the default timer. */ +int +_setup_low_level (void) +{ + _arc_timer_default_reset (); + + return 0; +} diff --git a/libgloss/arc/hl-stub.c b/libgloss/arc/hl-stub.c new file mode 100644 index 000000000..7f5b9facc --- /dev/null +++ b/libgloss/arc/hl-stub.c @@ -0,0 +1,81 @@ +/* + * hl-stub.c -- provide _kill() and _getpid(). + * + * Copyright (c) 2024 Synopsys Inc. + * + * The authors hereby grant permission to use, copy, modify, distribute, + * and license this software and its documentation for any purpose, provided + * that existing copyright notices are retained in all copies and that this + * notice is included verbatim in any distributions. No written agreement, + * license, or royalty fee is required for any of the authorized uses. + * Modifications to this software may be copyrighted by their authors + * and need not follow the licensing terms described here, provided that + * the new terms are clearly indicated on the first page of each file where + * they apply. + * + */ + +#include +#include +#include +#include +#include +#include + +#include "glue.h" + + +/* If PID is equal to __MYPID, exit with sig as retcode. */ +int +_kill (int pid, int sig) +{ + if (pid == __MYPID) + _exit (sig); + + errno = ENOSYS; + return -1; +} + + +/* Return __MYPID. */ +int +_getpid (void) +{ + return __MYPID; +} + + +/* hostlink backend has only fstat(), so use fstat() in stat(). */ +int +_stat (const char *pathname, struct stat *buf) +{ + int fd; + int ret; + int saved_errno; + + fd = open (pathname, O_RDONLY); + if (fd < 0) + { + /* errno is set by open(). */ + return -1; + } + + ret = fstat (fd, buf); + saved_errno = errno; + + close (fd); + + errno = saved_errno; + + return ret; +} + + +/* No Metaware hostlink backend for this call. */ +int +_link (const char *oldpath __attribute__ ((unused)), + const char *newpath __attribute__ ((unused))) +{ + errno = ENOSYS; + return -1; +} diff --git a/libgloss/arc/hl.specs b/libgloss/arc/hl.specs new file mode 100644 index 000000000..9bb5b7995 --- /dev/null +++ b/libgloss/arc/hl.specs @@ -0,0 +1,14 @@ +%rename link_gcc_c_sequence hl_link_gcc_c_sequence +%rename startfile hl_startfile + +*hl_libgloss: +-lhl + +*hl_libc: +%{!specs=nano.specs:-lc} %{specs=nano.specs:-lc_nano} + +*link_gcc_c_sequence: +%(hl_link_gcc_c_sequence) --start-group %G %(hl_libc) %(hl_libgloss) --end-group + +*startfile: +%(hl_startfile) arc-main-helper%O%s diff --git a/libgloss/arc/hl/hl_api.c b/libgloss/arc/hl/hl_api.c new file mode 100644 index 000000000..cb24fb997 --- /dev/null +++ b/libgloss/arc/hl/hl_api.c @@ -0,0 +1,350 @@ +/* + * hl_api.c -- high-level Hostlink IO API. + * + * Copyright (c) 2024 Synopsys Inc. + * + * The authors hereby grant permission to use, copy, modify, distribute, + * and license this software and its documentation for any purpose, provided + * that existing copyright notices are retained in all copies and that this + * notice is included verbatim in any distributions. No written agreement, + * license, or royalty fee is required for any of the authorized uses. + * Modifications to this software may be copyrighted by their authors + * and need not follow the licensing terms described here, provided that + * the new terms are clearly indicated on the first page of each file where + * they apply. + * + */ + +#include +#include + +#include "hl_gw.h" +#include "hl_api.h" + +/* Parameter types. */ +#define PAT_CHAR 1 +#define PAT_SHORT 2 +#define PAT_INT 3 +#define PAT_STRING 4 +/* For future use. */ +#define PAT_INT64 5 + +/* Used internally to pass user hostlink parameters to _hl_message(). */ +struct _hl_user_info { + uint32_t vendor_id; + uint32_t opcode; + uint32_t result; +}; + +/* + * Main function to send a message using hostlink. + * + * syscall - one of HL_SYSCALL_* defines from hl_api.h. + * + * user - parameters and return value for _user_hostlink implementation. + * Packing structure: + * uint32 vendor_id - user-defined vendor ID. ID 1025 is reserved for + * GNU IO extensions. + * uint32 opcode - operation code for user-defined hostlink. + * char format[] - argument string in the same format as for + * _hl_message() function, see below. + * + * format - argument and return values format string [(i4sp)*:?(i4sp)*], where + * characters before ':' is arguments and after is return values. + * Supported format characters: + * i or 4 - uint32 value, pack_int will be used; + * s - char * data, pack_str will be used; + * p - void * data, pack_ptr will be used. + * + * ap - argument values and pointers to the output values. Must be in sync + * with format string. + * For hostlink message argument: + * i or 4 - uint32 value; + * s - char * pointer to the NUL-teminated string; + * p - void * pointer to the buffer and uint32 buffer length. + * For output values: + * i or 4 - uint32 * pointer to uint32 to return; + * s - char * pointer to buffer to return, it must have enough + * space to store returned data. + * You can get packed buffer length with _hl_get_ptr_len(); + * p - void * pointer and uint32 * length pointer to store + * returned data along with length. Buffer must be enough + * to store returned data. + * You can get packed buffer length with _hl_get_ptr_len(); + * + * return - pointer to the hostlink buffer after output values. + */ +static volatile __uncached char * +_hl_message_va (uint32_t syscall, struct _hl_user_info *user, + const char *format, va_list ap) +{ + const char *f = format; + volatile __uncached char *p = _hl_payload (); + int get_answer = 0; + + p = _hl_pack_int (p, syscall); + + if (syscall == HL_SYSCALL_USER) + { + p = _hl_pack_int (p, user->vendor_id); + p = _hl_pack_int (p, user->opcode); + p = _hl_pack_str (p, format); + } + + for (; *f; f++) + { + void *ptr; + uint32_t len; + + if (*f == ':') + { + f++; + get_answer = 1; + break; + } + + switch (*f) + { + case 'i': + case '4': + p = _hl_pack_int (p, va_arg (ap, uint32_t)); + break; + case 's': + p = _hl_pack_str (p, va_arg (ap, char *)); + break; + case 'p': + ptr = va_arg (ap, void *); + len = va_arg (ap, uint32_t); + p = _hl_pack_ptr (p, ptr, len); + break; + default: + return NULL; + } + + if (p == NULL) + return NULL; + } + + _hl_send (p); + + p = _hl_recv (); + + if (syscall == HL_SYSCALL_USER && p) + p = _hl_unpack_int (p, &user->result); + + if (p && get_answer) + { + for (; *f; f++) + { + void *ptr; + uint32_t *plen; + + switch (*f) + { + case 'i': + case '4': + p = _hl_unpack_int (p, va_arg (ap, uint32_t *)); + break; + case 's': + p = _hl_unpack_str (p, va_arg (ap, char *)); + break; + case 'p': + ptr = va_arg (ap, void *); + plen = va_arg (ap, uint32_t *); + p = _hl_unpack_ptr (p, ptr, plen); + break; + default: + return NULL; + } + + if (p == NULL) + return NULL; + } + } + + return p; +} + +/* + * Pack integer value (uint32) to provided buffer. + * Packing structure: + * uint16 type (PAT_INT = 3) + * uint16 size (4) + * uint32 value + */ +volatile __uncached char * +_hl_pack_int (volatile __uncached char *p, uint32_t x) +{ + volatile __uncached uint16_t *type = (volatile __uncached uint16_t *) p; + volatile __uncached uint16_t *size = (volatile __uncached uint16_t *) + (p + 2); + volatile __uncached uint32_t *val = (volatile __uncached uint32_t *) + (p + 4); + const uint32_t payload_used = 8; + + if (_hl_payload_left (p) < payload_used) + return NULL; + + *type = PAT_INT; + *size = 4; + *val = x; + + return p + payload_used; +} + +/* + * Pack data (pointer and legth) to provided buffer. + * Packing structure: + * uint16 type (PAT_STRING = 4) + * uint16 size (length) + * char buf[length] + */ +volatile __uncached char * +_hl_pack_ptr (volatile __uncached char *p, const void *s, uint16_t len) +{ + volatile __uncached uint16_t *type = (volatile __uncached uint16_t *) p; + volatile __uncached uint16_t *size = (volatile __uncached uint16_t *) + (p + 2); + volatile __uncached char *buf = p + 4; + const uint32_t payload_used = 4 + ALIGN (len, 4); + + if (_hl_payload_left (p) < payload_used) + return NULL; + + *type = PAT_STRING; + *size = len; + + /* _vdmemcpy(buf, s, len); */ + for (uint16_t i = 0; i < len; i++) + buf[i] = ((const char *) s)[i]; + + return p + payload_used; +} + +/* + * Pack NUL-terminated string to provided buffer. + * Packing structure: + * uint16 type (PAT_STRING = 4) + * uint16 size (length) + * char buf[length] + */ +volatile __uncached char * +_hl_pack_str (volatile __uncached char *p, const char *s) +{ + return _hl_pack_ptr (p, s, strlen (s) + 1); +} + +/* Unpack integer value (uint32_t) from a buffer. */ +volatile __uncached char * +_hl_unpack_int (volatile __uncached char *p, uint32_t *x) +{ + volatile __uncached uint16_t *type = (volatile __uncached uint16_t *) p; + volatile __uncached uint16_t *size = (volatile __uncached uint16_t *) + (p + 2); + volatile __uncached uint32_t *val = (volatile __uncached uint32_t *) + (p + 4); + const uint32_t payload_used = 8; + + if (_hl_payload_left (p) < payload_used || *type != PAT_INT || *size != 4) + return NULL; + + if (x) + *x = *val; + + return p + payload_used; +} + +/* Unpack data from a buffer. */ +volatile __uncached char * +_hl_unpack_ptr (volatile __uncached char *p, void *s, uint32_t *plen) +{ + volatile __uncached uint16_t *type = (volatile __uncached uint16_t *) p; + volatile __uncached uint16_t *size = (volatile __uncached uint16_t *) + (p + 2); + volatile __uncached char *buf = p + 4; + uint32_t payload_used; + uint32_t len; + + if (_hl_payload_left (p) < 4 || *type != PAT_STRING) + return NULL; + + len = *size; + payload_used = 4 + ALIGN (len, 4); + + if (_hl_payload_left (p) < payload_used) + return NULL; + + if (plen) + *plen = len; + + /* _vsmemcpy(s, buf, len); */ + if (s) + { + for (uint32_t i = 0; i < len; i++) + ((char *) s)[i] = buf[i]; + } + + return p + payload_used; +} + +/* + * Unpack data from a buffer. + * + * No difference compared to _hl_unpack_ptr, except that this function + * does not return a length. + */ +volatile __uncached char * +_hl_unpack_str (volatile __uncached char *p, char *s) +{ + return _hl_unpack_ptr (p, s, NULL); +} + +/* Return length of packed data (PAT_STRING) if it is on top of the buffer. */ +uint32_t +_hl_get_ptr_len (volatile __uncached char *p) +{ + volatile __uncached uint16_t *type = (volatile __uncached uint16_t *) p; + volatile __uncached uint16_t *size = (volatile __uncached uint16_t *) + (p + 2); + + if (_hl_payload_left (p) < 4 || *type != PAT_STRING) + return 0; + + return *size; +} + +/* Public version of _hl_message_va(). */ +volatile __uncached char * +_hl_message (uint32_t syscall, const char *format, ...) +{ + va_list ap; + volatile __uncached char *p; + + va_start (ap, format); + + p = _hl_message_va (syscall, 0, format, ap); + + va_end (ap); + + return p; +} + +/* + * API to call user-defined hostlink. See description of user argument in + * _hl_message_va(). + */ +uint32_t +_user_hostlink (uint32_t vendor, uint32_t opcode, const char *format, ...) +{ + va_list ap; + struct _hl_user_info ui = { .vendor_id = vendor, + .opcode = opcode }; + + va_start (ap, format); + + _hl_message_va (HL_SYSCALL_USER, &ui, format, ap); + + va_end (ap); + + return ui.result; +} diff --git a/libgloss/arc/hl/hl_api.h b/libgloss/arc/hl/hl_api.h new file mode 100644 index 000000000..2f8846dc6 --- /dev/null +++ b/libgloss/arc/hl/hl_api.h @@ -0,0 +1,77 @@ +/* + * hl_api.h -- provide high-level API for Hostlink IO. + * + * Copyright (c) 2024 Synopsys Inc. + * + * The authors hereby grant permission to use, copy, modify, distribute, + * and license this software and its documentation for any purpose, provided + * that existing copyright notices are retained in all copies and that this + * notice is included verbatim in any distributions. No written agreement, + * license, or royalty fee is required for any of the authorized uses. + * Modifications to this software may be copyrighted by their authors + * and need not follow the licensing terms described here, provided that + * the new terms are clearly indicated on the first page of each file where + * they apply. + * + */ + +#include +#include "hl_toolchain.h" + +#ifndef _HL_API_H +#define _HL_API_H + +#define HL_SYSCALL_OPEN 0 +#define HL_SYSCALL_CLOSE 1 +#define HL_SYSCALL_READ 2 +#define HL_SYSCALL_WRITE 3 +#define HL_SYSCALL_LSEEK 4 +#define HL_SYSCALL_UNLINK 5 +#define HL_SYSCALL_ISATTY 6 +#define HL_SYSCALL_TMPNAM 7 +#define HL_SYSCALL_GETENV 8 +#define HL_SYSCALL_CLOCK 9 +#define HL_SYSCALL_TIME 10 +#define HL_SYSCALL_RENAME 11 +#define HL_SYSCALL_ARGC 12 +#define HL_SYSCALL_ARGV 13 +#define HL_SYSCALL_RETCODE 14 +#define HL_SYSCALL_ACCESS 15 +#define HL_SYSCALL_GETPID 16 +#define HL_SYSCALL_GETCWD 17 +#define HL_SYSCALL_USER 18 + +#define HL_GNUIO_EXT_VENDOR_ID 1025 + +#define HL_GNUIO_EXT_FSTAT 1 + +/* + * Main functions to work with regular syscalls and user-defined hostlink + * messages. + */ +volatile __uncached char *_hl_message (uint32_t syscall, + const char *format, ...); +uint32_t _user_hostlink (uint32_t vendor, uint32_t opcode, + const char *format, ...); + + +/* Fuctions for direct work with the Hostlink buffer. */ +volatile __uncached char *_hl_pack_int (volatile __uncached char *p, + uint32_t x); +volatile __uncached char *_hl_pack_ptr (volatile __uncached char *p, + const void *s, uint16_t len); +volatile __uncached char *_hl_pack_str (volatile __uncached char *p, + const char *s); +volatile __uncached char *_hl_unpack_int (volatile __uncached char *p, + uint32_t *x); +volatile __uncached char *_hl_unpack_ptr (volatile __uncached char *p, + void *s, uint32_t *plen); +volatile __uncached char *_hl_unpack_str (volatile __uncached char *p, + char *s); +uint32_t _hl_get_ptr_len (volatile __uncached char *p); + +/* Low-level functions from hl_gw. */ +extern uint32_t _hl_iochunk_size (void); +extern void _hl_delete (void); + +#endif /* !_HL_API_H */ diff --git a/libgloss/arc/hl/hl_argc.c b/libgloss/arc/hl/hl_argc.c new file mode 100644 index 000000000..9d17095b5 --- /dev/null +++ b/libgloss/arc/hl/hl_argc.c @@ -0,0 +1,45 @@ +/* + * hl_argc.c -- provide _argc(). + * + * Copyright (c) 2024 Synopsys Inc. + * + * The authors hereby grant permission to use, copy, modify, distribute, + * and license this software and its documentation for any purpose, provided + * that existing copyright notices are retained in all copies and that this + * notice is included verbatim in any distributions. No written agreement, + * license, or royalty fee is required for any of the authorized uses. + * Modifications to this software may be copyrighted by their authors + * and need not follow the licensing terms described here, provided that + * the new terms are clearly indicated on the first page of each file where + * they apply. + * + */ + +#include + +#include "hl_toolchain.h" +#include "hl_api.h" + +/* Implements HL_SYSCALL_ARGC. */ +static __always_inline int +_hl_argc (void) +{ + uint32_t ret; + volatile __uncached char *p; + + p = _hl_message (HL_SYSCALL_ARGC, ":i", (uint32_t *) &ret); + + if (p == NULL) + ret = 0; + + _hl_delete (); + + return ret; +} + +/* See arc-main-helper.c. */ +int +_argc (void) +{ + return _hl_argc (); +} diff --git a/libgloss/arc/hl/hl_argv.c b/libgloss/arc/hl/hl_argv.c new file mode 100644 index 000000000..1c1439cf9 --- /dev/null +++ b/libgloss/arc/hl/hl_argv.c @@ -0,0 +1,67 @@ +/* + * hl_argv.c -- provide _argv(). + * + * Copyright (c) 2024 Synopsys Inc. + * + * The authors hereby grant permission to use, copy, modify, distribute, + * and license this software and its documentation for any purpose, provided + * that existing copyright notices are retained in all copies and that this + * notice is included verbatim in any distributions. No written agreement, + * license, or royalty fee is required for any of the authorized uses. + * Modifications to this software may be copyrighted by their authors + * and need not follow the licensing terms described here, provided that + * the new terms are clearly indicated on the first page of each file where + * they apply. + * + */ + +#include + +#include "hl_toolchain.h" +#include "hl_api.h" + +/* Get buffer length for argv[a] using HL_SYSCALL_ARGV. */ +static __always_inline uint32_t +_hl_argvlen (int a) +{ + uint32_t ret = 0; + volatile __uncached char *p; + + p = _hl_message (HL_SYSCALL_ARGV, "i", (uint32_t) a); + if (p != NULL) + ret = _hl_get_ptr_len (p); + + _hl_delete (); + + return ret; +} + +/* Implements HL_SYSCALL_ARGV. */ +static __always_inline int +_hl_argv (int a, char *arg) +{ + int ret = 0; + volatile __uncached char *p; + + p = _hl_message (HL_SYSCALL_ARGV, "i:s", (uint32_t) a, (char *) arg); + if (p == NULL) + ret = -1; + + _hl_delete (); + + return ret; +} + +/* See arc-main-helper.c. */ +uint32_t +_argvlen (int a) +{ + return _hl_argvlen (a); +} + +/* See arc-main-helper.c. */ +int +_argv (int a, char *arg) +{ + return _hl_argv (a, arg); +} diff --git a/libgloss/arc/hl/hl_clock.c b/libgloss/arc/hl/hl_clock.c new file mode 100644 index 000000000..b71267296 --- /dev/null +++ b/libgloss/arc/hl/hl_clock.c @@ -0,0 +1,87 @@ +/* + * hl_clock.c -- provide _clock() and _times(). + * + * Copyright (c) 2024 Synopsys Inc. + * + * The authors hereby grant permission to use, copy, modify, distribute, + * and license this software and its documentation for any purpose, provided + * that existing copyright notices are retained in all copies and that this + * notice is included verbatim in any distributions. No written agreement, + * license, or royalty fee is required for any of the authorized uses. + * Modifications to this software may be copyrighted by their authors + * and need not follow the licensing terms described here, provided that + * the new terms are clearly indicated on the first page of each file where + * they apply. + * + */ + +#include +#include +#include +#include + +#include "../arc-timer.h" + +#include "hl_toolchain.h" +#include "hl_api.h" + +/* Implements HL_SYSCALL_CLOCK. */ +static __always_inline clock_t +_hl_clock (void) +{ + uint32_t ret; + volatile __uncached char *p; + + p = _hl_message (HL_SYSCALL_CLOCK, ":i", (uint32_t *) &ret); + + _hl_delete (); + + if (p == NULL) + { + errno = ETIMEDOUT; + return -1; + } + + return ret; +} + +/* + * This implementation returns timer 0 value if it exists or + * host clock() value converted to target clocks. + * + * Please note that this value cannot be converted to seconds + * using CLOCKS_PER_SEC. + */ +clock_t +_clock (void) +{ + if (_arc_timer_default_present ()) + return _arc_timer_default_read (); + else + return _hl_clock (); +} + +/* All time is counted as user time. */ +clock_t +_times (struct tms *tp) +{ + clock_t ret; + + if (tp == NULL) + { + errno = EFAULT; + return -1; + } + + ret = _clock (); + + if (ret == (clock_t) -1) + return ret; + + tp->tms_utime = ret; + tp->tms_stime = 0; + tp->tms_cutime = 0; + tp->tms_cstime = 0; + + return ret; +} diff --git a/libgloss/arc/hl/hl_close.c b/libgloss/arc/hl/hl_close.c new file mode 100644 index 000000000..c547e2d03 --- /dev/null +++ b/libgloss/arc/hl/hl_close.c @@ -0,0 +1,58 @@ +/* + * hl_close.c -- provide _close(). + * + * Copyright (c) 2024 Synopsys Inc. + * + * The authors hereby grant permission to use, copy, modify, distribute, + * and license this software and its documentation for any purpose, provided + * that existing copyright notices are retained in all copies and that this + * notice is included verbatim in any distributions. No written agreement, + * license, or royalty fee is required for any of the authorized uses. + * Modifications to this software may be copyrighted by their authors + * and need not follow the licensing terms described here, provided that + * the new terms are clearly indicated on the first page of each file where + * they apply. + * + */ + +#include +#include +#include + +#include "hl_toolchain.h" +#include "hl_api.h" + +/* Implements HL_SYSCALL_CLOSE. */ +static __always_inline int +_hl_close (int fd) +{ + int32_t ret; + uint32_t host_errno; + volatile __uncached char *p; + + p = _hl_message (HL_SYSCALL_CLOSE, "i:ii", + (uint32_t) fd, /* i */ + (uint32_t *) &ret, /* :i */ + (uint32_t *) &host_errno /* :i */); + + if (p == NULL) + { + errno = ETIMEDOUT; + ret = -1; + } + else if (ret < 0) + { + errno = host_errno; + ret = -1; + } + + _hl_delete (); + + return ret; +} + +int +_close (int fd) +{ + return _hl_close (fd); +} diff --git a/libgloss/arc/hl/hl_exit.c b/libgloss/arc/hl/hl_exit.c new file mode 100644 index 000000000..c42ada0fa --- /dev/null +++ b/libgloss/arc/hl/hl_exit.c @@ -0,0 +1,42 @@ +/* + * hl_exit.c -- provide _exit(). + * + * Copyright (c) 2024 Synopsys Inc. + * + * The authors hereby grant permission to use, copy, modify, distribute, + * and license this software and its documentation for any purpose, provided + * that existing copyright notices are retained in all copies and that this + * notice is included verbatim in any distributions. No written agreement, + * license, or royalty fee is required for any of the authorized uses. + * Modifications to this software may be copyrighted by their authors + * and need not follow the licensing terms described here, provided that + * the new terms are clearly indicated on the first page of each file where + * they apply. + * + */ + +#include +#include + +#include "hl_toolchain.h" +#include "hl_api.h" + +/* From crt0. */ +extern void __noreturn __longcall _exit_halt (void); + +/* Push retcode to host. Implements HL_SYSCALL_RETCODE. */ +static __always_inline void +_hl_retcode (int32_t ret) +{ + (void) _hl_message (HL_SYSCALL_RETCODE, "i", (uint32_t) ret); + + _hl_delete (); +} + +void __noreturn +_exit (int ret) +{ + _hl_retcode (ret); + + _exit_halt (); +} diff --git a/libgloss/arc/hl/hl_fstat.c b/libgloss/arc/hl/hl_fstat.c new file mode 100644 index 000000000..0a49eece0 --- /dev/null +++ b/libgloss/arc/hl/hl_fstat.c @@ -0,0 +1,95 @@ +/* + * hl_fstat.c -- provide _fstat(). + * + * Copyright (c) 2024 Synopsys Inc. + * + * The authors hereby grant permission to use, copy, modify, distribute, + * and license this software and its documentation for any purpose, provided + * that existing copyright notices are retained in all copies and that this + * notice is included verbatim in any distributions. No written agreement, + * license, or royalty fee is required for any of the authorized uses. + * Modifications to this software may be copyrighted by their authors + * and need not follow the licensing terms described here, provided that + * the new terms are clearly indicated on the first page of each file where + * they apply. + * + */ + +#include +#include +#include +#include +#include +#include + +#include "hl_toolchain.h" +#include "hl_api.h" + +/* Hostlink IO version of struct stat. */ +struct _hl_stat { + uint32_t hl_dev; /* ID of device containing file. */ + uint16_t hl_ino; /* inode number. */ + uint16_t hl_mode; /* File type and access mode. */ + int16_t hl_nlink; /* Number of hard links. */ + int16_t hl_uid; /* Owner's UID. */ + int16_t hl_gid; /* Owner's GID. */ + uint8_t hl_pad[2]; /* Padding to match simulator struct. */ + uint32_t hl_rdev; /* Device ID (if special file). */ + int32_t hl_size; /* Size in bytes. */ + int32_t hl_atime; /* Access time. */ + int32_t hl_mtime; /* Modification time. */ + int32_t hl_ctime; /* Creation time. */ +} __packed; + +/* Map Hostlink version of stat struct into newlib's one. */ +static __always_inline void +_hl_fstat_map (const struct _hl_stat *hl_stat, struct stat *stat) +{ + stat->st_dev = hl_stat->hl_dev; + stat->st_ino = hl_stat->hl_ino; + stat->st_mode = hl_stat->hl_mode; + stat->st_nlink = hl_stat->hl_nlink; + stat->st_uid = hl_stat->hl_uid; + stat->st_gid = hl_stat->hl_gid; + stat->st_rdev = hl_stat->hl_rdev; + stat->st_size = hl_stat->hl_size; + stat->st_atime = hl_stat->hl_atime; + stat->st_mtime = hl_stat->hl_mtime; + stat->st_ctime = hl_stat->hl_ctime; +} + +/* Get host file info. Implements HL_GNUIO_EXT_FSTAT. */ +static __always_inline int +_hl_fstat (int fd, struct stat *buf) +{ + struct _hl_stat hl_stat; + int32_t ret; + uint32_t host_errno; + + /* Special version of hostlink - retuned values are passed + * through inargs. + */ + host_errno = _user_hostlink (HL_GNUIO_EXT_VENDOR_ID, HL_GNUIO_EXT_FSTAT, + "iii", + (uint32_t) fd, + (uint32_t) &hl_stat, + (uint32_t) &ret); + + if (ret < 0) + { + errno = host_errno; + return ret; + } + + _hl_fstat_map (&hl_stat, buf); + + _hl_delete (); + + return ret; +} + +int +_fstat (int fd, struct stat *buf) +{ + return _hl_fstat (fd, buf); +} diff --git a/libgloss/arc/hl/hl_gettimeofday.c b/libgloss/arc/hl/hl_gettimeofday.c new file mode 100644 index 000000000..40c4c2bb0 --- /dev/null +++ b/libgloss/arc/hl/hl_gettimeofday.c @@ -0,0 +1,69 @@ +/* + * hl_gettimeofday.c -- provide _gettimeofday(). + * + * Copyright (c) 2024 Synopsys Inc. + * + * The authors hereby grant permission to use, copy, modify, distribute, + * and license this software and its documentation for any purpose, provided + * that existing copyright notices are retained in all copies and that this + * notice is included verbatim in any distributions. No written agreement, + * license, or royalty fee is required for any of the authorized uses. + * Modifications to this software may be copyrighted by their authors + * and need not follow the licensing terms described here, provided that + * the new terms are clearly indicated on the first page of each file where + * they apply. + * + */ + +#include +#include +#include +#include + +#include "hl_toolchain.h" +#include "hl_api.h" + +/* Get host time(). Implements HL_SYSCALL_TIME. */ +static __always_inline int +_hl_time (uint32_t *host_timer) +{ + int ret; + volatile __uncached char *p; + + p = _hl_message (HL_SYSCALL_TIME, ":i", (uint32_t *) host_timer); + + if (p == NULL) + { + errno = ETIMEDOUT; + ret = -1; + } + else + { + ret = 0; + } + + _hl_delete (); + + return ret; +} + +/* gettimeofday() implementation. Clears *tz if specified. */ +int +_gettimeofday (struct timeval *tv, struct timezone *tz) +{ + int ret; + uint32_t host_timer; + + if (tz) + memset (tz, 0, sizeof (*tz)); + + ret = _hl_time (&host_timer); + + if (ret == 0) + { + tv->tv_sec = host_timer; + tv->tv_usec = 0; + } + + return ret; +} diff --git a/libgloss/arc/hl/hl_gw.c b/libgloss/arc/hl/hl_gw.c new file mode 100644 index 000000000..f576f097e --- /dev/null +++ b/libgloss/arc/hl/hl_gw.c @@ -0,0 +1,180 @@ +/* + * hl_gw.c -- Hostlink gateway, low-level hostlink functions. + * + * Copyright (c) 2024 Synopsys Inc. + * + * The authors hereby grant permission to use, copy, modify, distribute, + * and license this software and its documentation for any purpose, provided + * that existing copyright notices are retained in all copies and that this + * notice is included verbatim in any distributions. No written agreement, + * license, or royalty fee is required for any of the authorized uses. + * Modifications to this software may be copyrighted by their authors + * and need not follow the licensing terms described here, provided that + * the new terms are clearly indicated on the first page of each file where + * they apply. + * + */ + +#include "hl_gw.h" + +#define HL_VERSION 1 + + +/* + * Maximum message size without service information, + * see also HL_PAYLOAD_RESERVED. + */ +#ifndef HL_IOCHUNK + #define HL_IOCHUNK 1024 +#endif + +/* + * Each syscall argument have 4 bytes of service information in hostlink + * protocol (2 bytes for type and 2 for size). Here we reserve space for + * 32 arguments. + */ +#define HL_PAYLOAD_RESERVED (32 * 4) + +/* "No message here" mark. */ +#define HL_NOADDRESS 0xFFFFFFFF + +/* Hostlink gateway structure. */ +struct _hl_hdr { + uint32_t version; /* Current version is 1. */ + uint32_t target2host_addr; /* Packet address from target to host. */ + uint32_t host2target_addr; /* Packet address from host to target. */ + uint32_t buf_addr; /* Address for host to write answer. */ + uint32_t payload_size; /* Buffer size without packet header. */ + uint32_t options; /* For future use. */ + uint32_t break_to_mon_addr; /* For future use. */ +} __uncached __packed; + +/* Hostlink packet header. */ +struct _hl_pkt_hdr { + uint32_t packet_id; /* Packet id. Always set to 1 here. */ + uint32_t total_size; /* Size of packet including header. */ + uint32_t priority; /* For future use. */ + uint32_t type; /* For future use. */ + uint32_t checksum; /* For future use. */ +} __uncached __packed; + +/* Main hostlink structure. */ +struct _hl { + volatile struct _hl_hdr hdr; /* General hostlink information. */ + /* Start of the hostlink buffer. */ + volatile struct _hl_pkt_hdr pkt_hdr; + volatile char payload[HL_IOCHUNK + HL_PAYLOAD_RESERVED]; +} __aligned (HL_MAX_DCACHE_LINE) __uncached __packed; + + +/* + * Main structure. Do not rename because simulator will look for the + * '__HOSTLINK__' symbol. + */ +volatile struct _hl __HOSTLINK__ = { + .hdr = { + .version = 1 , + .target2host_addr = HL_NOADDRESS + } +}; + +/* Get hostlink payload pointer. */ +volatile __uncached void * +_hl_payload (void) +{ + return (volatile __uncached void *) &__HOSTLINK__.payload[0]; +} + +/* Get hostlink payload size (iochunk + reserved space). */ +static uint32_t +_hl_payload_size (void) +{ + return sizeof (__HOSTLINK__.payload); +} + +/* Get used space size in the payload. */ +static uint32_t +_hl_payload_used (volatile __uncached void *p) +{ + return (volatile __uncached char *) p + - (volatile __uncached char *) _hl_payload (); +} + +/* Fill hostlink packet header. */ +static void +_hl_pkt_init (volatile __uncached struct _hl_pkt_hdr *pkt, int size) +{ + pkt->packet_id = 1; + pkt->total_size = ALIGN (size, 4) + sizeof (*pkt); + pkt->priority = 0; + pkt->type = 0; + pkt->checksum = 0; +} + +/* Get hostlink iochunk size. */ +uint32_t +_hl_iochunk_size (void) +{ + return HL_IOCHUNK; +} + +/* Get free space size in the payload. */ +uint32_t +_hl_payload_left (volatile __uncached void *p) +{ + return _hl_payload_size () - _hl_payload_used (p); +} + +/* Send hostlink packet to the host. */ +void +_hl_send (volatile __uncached void *p) +{ + volatile __uncached struct _hl_hdr *hdr = &__HOSTLINK__.hdr; + volatile __uncached struct _hl_pkt_hdr *pkt_hdr = &__HOSTLINK__.pkt_hdr; + + _hl_pkt_init (pkt_hdr, _hl_payload_used (p)); + + hdr->buf_addr = (uint32_t) pkt_hdr; + hdr->payload_size = _hl_payload_size (); + hdr->host2target_addr = HL_NOADDRESS; + hdr->version = HL_VERSION; + hdr->options = 0; + hdr->break_to_mon_addr = 0; + + /* This tells the debugger we have a command. + * It is responsibility of debugger to set this back to HL_NOADDRESS + * after receiving the packet. + * Please note that we don't wait here because some implementations + * use _hl_blockedPeek() function as a signal that we send a messege. + */ + hdr->target2host_addr = hdr->buf_addr; +} + +/* + * Wait for host response and return pointer to hostlink payload. + * Symbol _hl_blockedPeek() is used by the simulator as message signal. + */ +volatile __uncached char * __noinline +_hl_blockedPeek (void) +{ + while (__HOSTLINK__.hdr.host2target_addr == HL_NOADDRESS) + { + /* TODO: Timeout. */ + } + + return _hl_payload (); +} + +/* Get message from host. */ +volatile __uncached char * +_hl_recv (void) +{ + return _hl_blockedPeek (); +} + +/* Mark hostlink buffer as "No message here". */ +void +_hl_delete (void) +{ + __HOSTLINK__.hdr.target2host_addr = HL_NOADDRESS; +} diff --git a/libgloss/arc/hl/hl_gw.h b/libgloss/arc/hl/hl_gw.h new file mode 100644 index 000000000..b019ee038 --- /dev/null +++ b/libgloss/arc/hl/hl_gw.h @@ -0,0 +1,46 @@ +/* + * hl_gw.h -- Hostlink gateway, low-level hostlink functions. + * This header should not be used directly, please use hl_api.h instead. + * + * Copyright (c) 2024 Synopsys Inc. + * + * The authors hereby grant permission to use, copy, modify, distribute, + * and license this software and its documentation for any purpose, provided + * that existing copyright notices are retained in all copies and that this + * notice is included verbatim in any distributions. No written agreement, + * license, or royalty fee is required for any of the authorized uses. + * Modifications to this software may be copyrighted by their authors + * and need not follow the licensing terms described here, provided that + * the new terms are clearly indicated on the first page of each file where + * they apply. + * + */ + +#ifndef _HL_GW_H +#define _HL_GW_H + +#include + +#include "hl_toolchain.h" + +/* Get hostlink payload pointer and size available for using. */ +volatile __uncached void *_hl_payload (void); + +/* Maximum amount of data that can be sent via hostlink in one message. */ +uint32_t _hl_iochunk_size (void); + +/* + * How many bytes are available in the hostlink payload buffer. + * This may be bigger than iochunk size because hostlink payload also contains + * reserved space for service information. + */ +uint32_t _hl_payload_left (volatile __uncached void *p); + +/* Send and receive hostlink packet. */ +void _hl_send (volatile __uncached void *p); +volatile __uncached char *_hl_recv (void); + +/* Mark target2host buffer as "No message here". */ +void _hl_delete (void); + +#endif /* !_HL_GW_H */ diff --git a/libgloss/arc/hl/hl_isatty.c b/libgloss/arc/hl/hl_isatty.c new file mode 100644 index 000000000..ad4a42e5f --- /dev/null +++ b/libgloss/arc/hl/hl_isatty.c @@ -0,0 +1,64 @@ +/* + * hl_isatty.c -- provide _isatty(). + * + * Copyright (c) 2024 Synopsys Inc. + * + * The authors hereby grant permission to use, copy, modify, distribute, + * and license this software and its documentation for any purpose, provided + * that existing copyright notices are retained in all copies and that this + * notice is included verbatim in any distributions. No written agreement, + * license, or royalty fee is required for any of the authorized uses. + * Modifications to this software may be copyrighted by their authors + * and need not follow the licensing terms described here, provided that + * the new terms are clearly indicated on the first page of each file where + * they apply. + * + */ + +#include +#include +#include + +#include "hl_toolchain.h" +#include "hl_api.h" + +/* Check if fd is a tty on the host. Implements HL_SYSCALL_ISATTY. */ +static __always_inline int +_hl_isatty (int fd) +{ + int32_t ret; + uint32_t host_errno; + volatile __uncached char *p; + + p = _hl_message (HL_SYSCALL_ISATTY, "i:ii", + (uint32_t) fd, /* i */ + (uint32_t *) &ret, /* :i */ + (uint32_t *) &host_errno /* :i */); + + if (p == NULL) + { + errno = ETIMEDOUT; + ret = 0; + } + /* isatty() returns 1 if fd is a terminal; + * otherwise it returns 0 and set errno. + */ + else if (ret == 0) + { + errno = host_errno; + } + else + { + ret = 1; + } + + _hl_delete (); + + return ret; +} + +int +_isatty (int fd) +{ + return _hl_isatty (fd); +} diff --git a/libgloss/arc/hl/hl_lseek.c b/libgloss/arc/hl/hl_lseek.c new file mode 100644 index 000000000..ef8df9382 --- /dev/null +++ b/libgloss/arc/hl/hl_lseek.c @@ -0,0 +1,68 @@ +/* + * hl_lseek.c -- provide _lseek(). + * + * Copyright (c) 2024 Synopsys Inc. + * + * The authors hereby grant permission to use, copy, modify, distribute, + * and license this software and its documentation for any purpose, provided + * that existing copyright notices are retained in all copies and that this + * notice is included verbatim in any distributions. No written agreement, + * license, or royalty fee is required for any of the authorized uses. + * Modifications to this software may be copyrighted by their authors + * and need not follow the licensing terms described here, provided that + * the new terms are clearly indicated on the first page of each file where + * they apply. + * + */ + +#include +#include +#include +#include +#include + +#include "hl_toolchain.h" +#include "hl_api.h" + + +/* Implements HL_SYSCALL_LSEEK. */ +static __always_inline off_t +_hl_lseek (int fd, off_t offset, int whence) +{ + ssize_t ret; + int32_t n; + uint32_t host_errno; + volatile __uncached char *p; + + p = _hl_message (HL_SYSCALL_LSEEK, "iii:ii", + (uint32_t) fd, /* i */ + (uint32_t) offset, /* i */ + (int32_t) whence, /* i */ + (uint32_t *) &n, /* :i */ + (uint32_t *) &host_errno /* :i */); + + if (p == NULL) + { + errno = ETIMEDOUT; + ret = -1; + } + else if (n < 0) + { + errno = host_errno; + ret = -1; + } + else + { + ret = n; + } + + _hl_delete (); + + return ret; +} + +off_t +_lseek (int fd, off_t offset, int whence) +{ + return _hl_lseek (fd, offset, whence); +} diff --git a/libgloss/arc/hl/hl_open.c b/libgloss/arc/hl/hl_open.c new file mode 100644 index 000000000..62cbe9db4 --- /dev/null +++ b/libgloss/arc/hl/hl_open.c @@ -0,0 +1,89 @@ +/* + * hl_open.c -- provide _open(). + * + * Copyright (c) 2024 Synopsys Inc. + * + * The authors hereby grant permission to use, copy, modify, distribute, + * and license this software and its documentation for any purpose, provided + * that existing copyright notices are retained in all copies and that this + * notice is included verbatim in any distributions. No written agreement, + * license, or royalty fee is required for any of the authorized uses. + * Modifications to this software may be copyrighted by their authors + * and need not follow the licensing terms described here, provided that + * the new terms are clearly indicated on the first page of each file where + * they apply. + * + */ + +#include +#include +#include +#include +#include +#include + +#include "hl_toolchain.h" +#include "hl_api.h" + +/* Map newlib open flags into Hostlink IO ones. */ +static __always_inline uint32_t +_hl_open_flags_map (int flags) +{ + uint32_t hl_flags = 0; + + hl_flags |= (flags & O_RDONLY) ? 0x0000 : 0; + hl_flags |= (flags & O_WRONLY) ? 0x0001 : 0; + hl_flags |= (flags & O_RDWR) ? 0x0002 : 0; + hl_flags |= (flags & O_APPEND) ? 0x0008 : 0; + hl_flags |= (flags & O_CREAT) ? 0x0100 : 0; + hl_flags |= (flags & O_TRUNC) ? 0x0200 : 0; + hl_flags |= (flags & O_EXCL) ? 0x0400 : 0; + + return hl_flags; +} + +/* Open file on host. Implements HL_SYSCALL_OPEN. */ +static __always_inline int +_hl_open (const char *path, int flags, mode_t mode) +{ + int32_t fd; + uint32_t host_errno; + uint32_t hl_flags = _hl_open_flags_map (flags); + volatile __uncached char *p; + + p = _hl_message (HL_SYSCALL_OPEN, "sii:ii", + path, /* s */ + (uint32_t) hl_flags, /* i */ + (uint32_t) mode, /* i */ + (uint32_t *) &fd, /* :i */ + (uint32_t *) &host_errno /* :i */); + + if (p == NULL) + { + errno = ETIMEDOUT; + fd = -1; + } + else if (fd < 0) + { + errno = host_errno; + fd = -1; + } + + _hl_delete (); + + return fd; +} + +int +_open (const char *path, int flags, ...) +{ + va_list ap; + mode_t mode = 0; + + va_start (ap, flags); + + if (flags & O_CREAT) + mode = va_arg (ap, mode_t); + + return _hl_open (path, flags, mode); +} diff --git a/libgloss/arc/hl/hl_read.c b/libgloss/arc/hl/hl_read.c new file mode 100644 index 000000000..584df1cce --- /dev/null +++ b/libgloss/arc/hl/hl_read.c @@ -0,0 +1,105 @@ +/* + * hl_read.c -- provide _read(). + * + * Copyright (c) 2024 Synopsys Inc. + * + * The authors hereby grant permission to use, copy, modify, distribute, + * and license this software and its documentation for any purpose, provided + * that existing copyright notices are retained in all copies and that this + * notice is included verbatim in any distributions. No written agreement, + * license, or royalty fee is required for any of the authorized uses. + * Modifications to this software may be copyrighted by their authors + * and need not follow the licensing terms described here, provided that + * the new terms are clearly indicated on the first page of each file where + * they apply. + * + */ + +#include +#include +#include +#include + +#include "hl_toolchain.h" +#include "hl_api.h" + + +/* Read one chunk. Implements HL_SYSCALL_READ. */ +static ssize_t +_hl_read (int fd, void *buf, size_t count) +{ + ssize_t ret; + int32_t hl_n; + uint32_t host_errno; + volatile __uncached char *p; + + p = _hl_message (HL_SYSCALL_READ, "ii:i", + (uint32_t) fd, /* i */ + (uint32_t) count, /* i */ + (uint32_t *) &hl_n /* :i */); + + if (p == NULL) + { + errno = ETIMEDOUT; + ret = -1; + } + else if (hl_n < 0) + { + p = _hl_unpack_int (p, &host_errno); + errno = p == NULL ? EIO : host_errno; + ret = -1; + } + else + { + uint32_t n; + + p = _hl_unpack_ptr (p, buf, &n); + ret = n; + + if (p == NULL || n != (uint32_t) hl_n) + { + errno = EIO; + ret = -1; + } + } + + _hl_delete (); + + return ret; +} + +ssize_t +_read (int fd, void *buf, size_t count) +{ + const uint32_t hl_iochunk = _hl_iochunk_size (); + size_t to_read = count; + size_t offset = 0; + ssize_t ret = 0; + + while (to_read > hl_iochunk) + { + ret = _hl_read (fd, (char *) buf + offset, hl_iochunk); + + if (ret < 0) + return ret; + + offset += ret; + + if (ret != (ssize_t) hl_iochunk) + return offset; + + to_read -= hl_iochunk; + } + + if (to_read) + { + ret = _hl_read (fd, (char *) buf + offset, to_read); + + if (ret < 0) + return ret; + + ret += offset; + } + + return ret; +} diff --git a/libgloss/arc/hl/hl_toolchain.h b/libgloss/arc/hl/hl_toolchain.h new file mode 100644 index 000000000..bf884bf3f --- /dev/null +++ b/libgloss/arc/hl/hl_toolchain.h @@ -0,0 +1,53 @@ +/* + * hl_toolchain.h -- provide toolchain-dependent defines. + * + * Copyright (c) 2024 Synopsys Inc. + * + * The authors hereby grant permission to use, copy, modify, distribute, + * and license this software and its documentation for any purpose, provided + * that existing copyright notices are retained in all copies and that this + * notice is included verbatim in any distributions. No written agreement, + * license, or royalty fee is required for any of the authorized uses. + * Modifications to this software may be copyrighted by their authors + * and need not follow the licensing terms described here, provided that + * the new terms are clearly indicated on the first page of each file where + * they apply. + * + */ + +#ifndef _HL_TOOLCHAIN_H +#define _HL_TOOLCHAIN_H + +#ifndef __uncached + #define __uncached __attribute__((uncached)) +#endif /* __uncached */ + +#ifndef __aligned + #define __aligned(x) __attribute__((aligned (x))) +#endif /* __aligned */ + +#ifndef __noinline + #define __noinline __attribute__((noinline)) +#endif /* __noinline */ + +#ifndef __always_inline + #define __always_inline inline __attribute__((always_inline)) +#endif /* __always_inline */ + +#ifndef __packed + #define __packed __attribute__((packed)) +#endif /* __packed */ + +#ifndef __noreturn + #define __noreturn __attribute__((noreturn)) +#endif /* __noreturn */ + +#ifndef __longcall + #define __longcall __attribute__((long_call)) +#endif /* __longcall */ + +#define HL_MAX_DCACHE_LINE 256 + +#define ALIGN(x, y) (((x) + ((y) - 1)) & ~((y) - 1)) + +#endif /* !_HL_TOOLCHAIN_H */ diff --git a/libgloss/arc/hl/hl_unlink.c b/libgloss/arc/hl/hl_unlink.c new file mode 100644 index 000000000..43393c517 --- /dev/null +++ b/libgloss/arc/hl/hl_unlink.c @@ -0,0 +1,59 @@ +/* + * hl_unlink.c -- provide _unlink(). + * + * Copyright (c) 2024 Synopsys Inc. + * + * The authors hereby grant permission to use, copy, modify, distribute, + * and license this software and its documentation for any purpose, provided + * that existing copyright notices are retained in all copies and that this + * notice is included verbatim in any distributions. No written agreement, + * license, or royalty fee is required for any of the authorized uses. + * Modifications to this software may be copyrighted by their authors + * and need not follow the licensing terms described here, provided that + * the new terms are clearly indicated on the first page of each file where + * they apply. + * + */ + +#include +#include +#include + +#include "hl_toolchain.h" +#include "hl_api.h" + + +/* Unlink host file. Implements HL_SYSCALL_UNLINK. */ +static __always_inline int +_hl_unlink (const char *path) +{ + int32_t ret; + uint32_t host_errno; + volatile __uncached char *p; + + p = _hl_message (HL_SYSCALL_UNLINK, "s:ii", + path, /* s */ + (uint32_t *) &ret, /* :i */ + (uint32_t *) &host_errno /* :i */); + + if (p == NULL) + { + errno = ETIMEDOUT; + ret = -1; + } + else if (ret < 0) + { + errno = host_errno; + ret = -1; + } + + _hl_delete (); + + return ret; +} + +int +_unlink (const char *path) +{ + return _hl_unlink (path); +} diff --git a/libgloss/arc/hl/hl_write.c b/libgloss/arc/hl/hl_write.c new file mode 100644 index 000000000..b00fc13e7 --- /dev/null +++ b/libgloss/arc/hl/hl_write.c @@ -0,0 +1,97 @@ +/* + * hl_write.c -- provide _write(). + * + * Copyright (c) 2024 Synopsys Inc. + * + * The authors hereby grant permission to use, copy, modify, distribute, + * and license this software and its documentation for any purpose, provided + * that existing copyright notices are retained in all copies and that this + * notice is included verbatim in any distributions. No written agreement, + * license, or royalty fee is required for any of the authorized uses. + * Modifications to this software may be copyrighted by their authors + * and need not follow the licensing terms described here, provided that + * the new terms are clearly indicated on the first page of each file where + * they apply. + * + */ + +#include +#include +#include +#include + +#include "hl_toolchain.h" +#include "hl_api.h" + + +/* Write one chunk to the host file. Implements HL_SYSCALL_WRITE. */ +static ssize_t +_hl_write (int fd, const char *buf, size_t nbyte) +{ + ssize_t ret; + int32_t n; + uint32_t host_errno; + volatile __uncached char *p; + + p = _hl_message (HL_SYSCALL_WRITE, "ipi:ii", + (uint32_t) fd, /* i */ + buf, (uint32_t) nbyte, /* p */ + (uint32_t) nbyte, /* i */ + (uint32_t *) &n, /* :i */ + (uint32_t *) &host_errno /* :i */); + + if (p == NULL) + { + errno = ETIMEDOUT; + ret = -1; + } + else if (n < 0) + { + errno = host_errno; + ret = -1; + } + else + { + ret = n; + } + + _hl_delete (); + + return ret; +} + +ssize_t +_write (int fd, const char *buf, size_t nbyte) +{ + const uint32_t hl_iochunk = _hl_iochunk_size (); + size_t to_write = nbyte; + size_t offset = 0; + ssize_t ret = 0; + + while (to_write > hl_iochunk) + { + ret = _hl_write (fd, buf + offset, hl_iochunk); + + if (ret < 0) + return ret; + + offset += ret; + + if (ret != (ssize_t) hl_iochunk) + return offset; + + to_write -= hl_iochunk; + } + + if (to_write) + { + ret = _hl_write (fd, buf + offset, to_write); + + if (ret < 0) + return ret; + + ret += offset; + } + + return ret; +} diff --git a/libgloss/arc/libcfunc.c b/libgloss/arc/libcfunc.c index c6e64f2b7..78bd76def 100644 --- a/libgloss/arc/libcfunc.c +++ b/libgloss/arc/libcfunc.c @@ -1,5 +1,5 @@ /* - Copyright (c) 2015, Synopsys, Inc. All rights reserved. + Copyright (c) 2015-2023, Synopsys, Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -75,7 +75,7 @@ unsigned __attribute__((weak)) sleep (unsigned seconds) { clock_t t0 = _clock (); - clock_t dt = seconds * CLOCKS_PER_SEC; + clock_t dt = (clock_t) seconds * CLOCKS_PER_SEC; while (_clock () - t0 < dt); return 0; @@ -85,7 +85,7 @@ int __attribute__((weak)) usleep (useconds_t useconds) { clock_t t0 = _clock (); - clock_t dt = useconds / (1000000/CLOCKS_PER_SEC); + clock_t dt = (clock_t) useconds / (1000000/CLOCKS_PER_SEC); while (_clock () - t0 < dt); return 0; diff --git a/libgloss/arc/readme-hostlink.md b/libgloss/arc/readme-hostlink.md new file mode 100644 index 000000000..0061be3df --- /dev/null +++ b/libgloss/arc/readme-hostlink.md @@ -0,0 +1,90 @@ +Metaware hostlink IO +==================== + +This directory includes target-side implementation of Metaware hostlink +interface see Contents section. Target program can use Metaware hostlink +interface to send messages to nsim simulator or mdb debugger (it can be +attached to HW or nsim). + +Quick start +----------- +To link with this version of libgloss please add `-specs=hl.specs` to baremetal +version of ARC gcc (arc-elf32). + +Lets build and run simple program: + + $ cat hello.c + #include + + int main() + { + printf("Hello World!\n"); + + return 0; + } + $ arc-elf32-gcc -mcpu=hs -specs=hl.specs ./hello.c -o hello + $ nsimdrv -prop=nsim_isa_family=av2hs -prop=nsim_hlink_gnu_io_ext=1 ./hello + Hello World! + +Where `-mcpu` and `-prop=nsim_isa_family` is specific to your version of ARC CPU. +Option `-prop=nsim_hlink_gnu_io_ext=1` enables GNU IO extension for nSIM which +is used for some system calls. The `nsimdrv` option `-prop=nsim_emt={0,1,2}` +enables trap emulation and should be disabled (removed or set to `0`) to use +Metaware hostlink. + +**NB:** Metaware hostlink requires symbols `__HOSTLINK__` and `_hl_blockedPeek` +to be present. So stripped binary won't work properly with Metaware hostlink. + +Contents +-------- +* `hl/hl_gw.*` -- Hostlink gateway. This API is used in the `hl_api.*`. + Please use `hl_message()` from `hl_api.*` for hostlink + message exchange. +* `hl/hl_api.*` -- High-level API to send hostlink messages, as well as + functions to work with messages. +* `hl/hl_.*` -- Syscall implementations through hostlink API; +* `arc-timer.*` -- Provides API to access ARC timers. Used by + `hl/hl_clock.c` in `_clock()` implementation. +* `arc-main-helper.c` -- Provides `__setup_argv_and_call_main()`. The function + is called from `__start()` in `crt0.S`. It allows + to setup `argc` and `arvg` as well as some custom + things through `_setup_low_level()`. +* `hl-setup.c` -- Provides `_setup_low_level()` for hostlink case. + It just configures default timer if it exists. Default + timer is used in the hostlink `clock()` + implementation. +* `hl-stub.c` -- Provides functions which are part of newlib but + implemented without hostlink. + e.g. `_kill()` and `_getpid()`. +* `sbrk.c` -- Provides `_sbrk()`. It uses `__start_heap` and + `__end_heap` variables. +* `libcfunc.c` -- Additional C system calls. +* `mcount.c` -- Profiler support. + +How it works +------------ +Simulator looks for `__HOSTLINK__` and `_hl_blockedPeek()` symbols. +`__HOSTLINK__` is the start of shared structure for message exchange and +`_hl_blockedPeek()` is a function to be called when program is waiting +for simulator response. + +When program wants to send a message it should follow: + 1. Fill `__HOSTLINK__.payload` with packed data. + Packing format is following: `{u16 type, u16 size, char data[]}`. + Supported types are `char`, `short`, `int`, `string` and `int64`. + `hl_api` provides high-level API to this. + 2. Fill `__HOSTLINK__.pkt_hdr`. See `hl_pkt_init()` from `hl_gw.c`. + 3. Fill `__HOSTLINK__.hdr`. See `hl_send()` from `hl_gw.c`. + 4. Call `_hl_blockedPeek()` to get response. + At this point message should be delivered to debugger. + Some implementations uses change of `__HOSTLINK__.hdr.target2host_addr` as + a signal that packet is sent and can be processed. Other implementations + wait for `_hl_blockedPeek()` to be called. + + It means that portable implementation must fill + `__HOSTLINK__.hdr.target2host_addr` at the last step and then call + `_hl_blockedPeek()`. + 5. `_hl_blockedPeek()` returns pointer to debugger response which can be + processed on target if needed. Because debugger and target share the same + buffer the function actually returns `__HOSTLINK__.payload` that was + filled with packed data (see step 1) by the debugger. -- 2.43.5