4
0
mirror of git://sourceware.org/git/newlib-cygwin.git synced 2025-02-08 18:19:08 +08:00
Vladimir Isaev 6d5331054e 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 <vvisaev@gmail.com>
2024-05-22 14:25:44 -04:00

181 lines
4.8 KiB
C

/*
* 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;
}