236 lines
8.4 KiB
C
236 lines
8.4 KiB
C
/*
|
|
Copyright (c) 2015, 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:
|
|
|
|
1) Redistributions of source code must retain the above copyright notice,
|
|
this list of conditions and the following disclaimer.
|
|
|
|
2) Redistributions in binary form must reproduce the above copyright notice,
|
|
this list of conditions and the following disclaimer in the documentation
|
|
and/or other materials provided with the distribution.
|
|
|
|
3) Neither the name of the Synopsys, Inc., nor the names of its contributors
|
|
may be used to endorse or promote products derived from this software
|
|
without specific prior written permission.
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include <_ansi.h>
|
|
#include <_syslist.h>
|
|
#include <errno.h>
|
|
#include <sys/fcntl.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/time.h>
|
|
#include <sys/times.h>
|
|
#include <sys/types.h>
|
|
|
|
#include "glue.h"
|
|
#include "nsim-syscall.h"
|
|
|
|
/* Those system calls are implemented in both nSIM and CGEN. */
|
|
_syscall3 (_ssize_t, read, int, fd, void *, buf, size_t, count)
|
|
_syscall3 (_ssize_t, write, int, fd, const void *, buf, size_t, count)
|
|
_syscall1 (int, unlink, const char *, pathname)
|
|
_syscall3 (off_t, lseek, int, fd, off_t, offset, int, whence)
|
|
_syscall2 (int, gettimeofday, struct timeval *, tv, void *, tz)
|
|
_syscall1 (_CLOCK_T_, time, _CLOCK_T_ *, t)
|
|
_syscall1 (int, close, int, fd)
|
|
_syscall1 (_CLOCK_T_, times, struct tms *, buf)
|
|
/* stat requires custom implementation. */
|
|
/* _syscall2 (int, stat, const char *, path, struct stat *, st)
|
|
_syscall2 (int, fstat, int, file, struct stat *, st) */
|
|
/* nSIM implements brk and sbrk, but instead sbrk.c is used. */
|
|
/* _syscall1 (int, brk, void *, addr) */
|
|
/* open requires custom implementation. */
|
|
/* _syscall3 (int, open, const char *, pathname, int, flags, int, mode) */
|
|
|
|
/* Those syscalls are not available in CGEN simulator. */
|
|
_syscall1 (int, rmdir, const char *, pathname)
|
|
_syscall2 (char *, getcwd, char *, buf, size_t, size)
|
|
/* stat requires custom implementation. */
|
|
/* _syscall2 (int, lstat, const char *, path, struct stat *, st) */
|
|
|
|
/* Historically "open" flags defined by default in newlib and in Linux for ARC
|
|
are different - this is true for some other architectures as well, e.g.
|
|
ARM. To provide compatibility ARC port of newlib had a custom fcntl.h file
|
|
that has "open" flags identical to Linux ones. Some other architectures
|
|
(spart64, cris) override default fcntl.h as well, but I'm not sure this is
|
|
really a good idea. Unlike system call numbers that can be unique to each
|
|
BSP in libgloss, "open" flags are not abstracted from the application code
|
|
itself, hence it is not possible to have fcntl.h in the libgloss. To make
|
|
matters worse, existing simulators already has been built for the Linux-like
|
|
"open" flags. To preserve compatibility with existing hostlink
|
|
implementations in simulators, but avoid custom fcntl.h in the future,
|
|
simulator BSP has to do dynamic rewriting of "open" flags from the newlib
|
|
default into old ARC Linux flags. Simulators support only most basic flags,
|
|
therefore only those are translated in this implementation. */
|
|
int
|
|
_open (const char * pathname, int flags, int mode)
|
|
{
|
|
int nsim_flags = 0;
|
|
|
|
/* RDONLY, WRONLY, RDWR are same as newlib default. */
|
|
nsim_flags |= flags & O_RDONLY;
|
|
nsim_flags |= flags & O_WRONLY;
|
|
nsim_flags |= flags & O_RDWR;
|
|
nsim_flags |= (flags & O_CREAT) ? ARC_LINUX_CREAT : 0;
|
|
nsim_flags |= (flags & O_APPEND) ? ARC_LINUX_APPEND : 0;
|
|
nsim_flags |= (flags & O_TRUNC) ? ARC_LINUX_TRUNC : 0;
|
|
nsim_flags |= (flags & O_EXCL) ? ARC_LINUX_EXCL : 0;
|
|
/* There are other fcntl flags that are different between newlib and ARC
|
|
uClibc, however they are not supported by nSIM hostlink, therefore there
|
|
is no need to translate them. */
|
|
|
|
long __res;
|
|
_naked_syscall3 (__res, open, pathname, nsim_flags, mode)
|
|
return __res;
|
|
}
|
|
|
|
/* Should be provided by crt0.S. */
|
|
extern void __attribute__((noreturn)) _exit_halt ();
|
|
|
|
void
|
|
__attribute__((noreturn))
|
|
_exit (int ret)
|
|
{
|
|
/* Doing an "exit" system call would work on nSIM with hostlink, but call to
|
|
_exit_halt, which will do a CPU halt is more universal and will work in
|
|
many other cases as well, including an FPGA/SoC. */
|
|
_exit_halt ();
|
|
}
|
|
|
|
/* This is a copy of newlib/libc/posix/_isatty.c. It is needed because nSIM
|
|
hostlink doesn't implement isatty system call. Hardware boards on the other
|
|
hand would want isatty implementation that always returns 1, since they are
|
|
connected to console and doesn't have file IO. */
|
|
int
|
|
_isatty (int fd)
|
|
{
|
|
struct stat buf;
|
|
|
|
if (fstat (fd, &buf) < 0)
|
|
{
|
|
errno = EBADF;
|
|
return 0;
|
|
}
|
|
if (S_ISCHR (buf.st_mode))
|
|
{
|
|
return 1;
|
|
}
|
|
errno = ENOTTY;
|
|
return 0;
|
|
}
|
|
|
|
/* System call "getpid" is implemented in nSIM hostlink, but it is better not
|
|
to expose it in libgloss. */
|
|
int
|
|
_getpid (void)
|
|
{
|
|
return __MYPID;
|
|
}
|
|
|
|
/* System call "kill" is implemented in nSIM hostlink on Linux hosts, but it
|
|
seems dangerous to expose it. Instead, like most of the other "_kill"
|
|
implementations in libgloss, this will kill only self. */
|
|
int
|
|
_kill (int pid, int sig)
|
|
{
|
|
if (pid == __MYPID)
|
|
{
|
|
_exit (sig);
|
|
}
|
|
errno = ENOSYS;
|
|
return -1;
|
|
}
|
|
|
|
static void
|
|
translate_stat (struct nsim_stat *nsim, struct stat *buf)
|
|
{
|
|
#define TR(field, type) buf->st_ ## field = (type) nsim->field
|
|
TR (dev, dev_t);
|
|
TR (ino, ino_t);
|
|
TR (mode, mode_t);
|
|
TR (nlink, nlink_t);
|
|
TR (uid, uid_t);
|
|
TR (gid, gid_t);
|
|
TR (rdev, dev_t);
|
|
TR (size, off_t);
|
|
TR (atime, time_t);
|
|
TR (mtime, time_t);
|
|
TR (ctime, time_t);
|
|
TR (blksize, long);
|
|
TR (blocks, long);
|
|
#undef TR
|
|
}
|
|
|
|
/* stat/fstat implementation. Situation is similiar to open and its flags -
|
|
structure is defined in libc, hence cannot be customized in libgloss, yet we
|
|
have a case where nSIM uses some definition which is not compatible with
|
|
neither old ARC-custom definition of "struct stat" in newlib, nor with
|
|
generic newlib implementation. */
|
|
int
|
|
_stat (const char * path, struct stat *buf)
|
|
{
|
|
struct nsim_stat nsim_stat;
|
|
long __res;
|
|
_naked_syscall2 (__res, stat, path, &nsim_stat)
|
|
translate_stat (&nsim_stat, buf);
|
|
return __res;
|
|
}
|
|
|
|
int
|
|
_lstat (const char * path, struct stat *buf)
|
|
{
|
|
struct nsim_stat nsim_stat;
|
|
long __res;
|
|
_naked_syscall2 (__res, stat, path, &nsim_stat)
|
|
translate_stat (&nsim_stat, buf);
|
|
return __res;
|
|
}
|
|
|
|
int
|
|
_fstat (int fd, struct stat *buf)
|
|
{
|
|
struct nsim_stat nsim_stat;
|
|
long __res;
|
|
_naked_syscall2 (__res, stat, fd, &nsim_stat)
|
|
translate_stat (&nsim_stat, buf);
|
|
return __res;
|
|
}
|
|
|
|
/* Some system calls are implemented in nSIM hostlink, but are available only
|
|
on Linux hosts. To minimize potential compatibility issues they are by
|
|
default disabled in libgloss build. */
|
|
#ifdef ARC_NSIM_WIN32_HOST
|
|
_syscall3 (int, ioctl, int, fd, int, request, char *, argp)
|
|
_syscall3 (_ssize_t, readv, int, fd, const struct iovec *, iov, int, iovcnt)
|
|
_syscall3 (_ssize_t, writev, int, fd, const struct iovec *, iov, int, iovcnt)
|
|
_syscall5 (off_t, llseek, int, fd, unsigned long, offset_high,
|
|
unsigned long, offset_low, loff_t *, result,
|
|
unsigned int, whence)
|
|
_syscall2 (int, getrusage, int, who, struct rusage *, usage)
|
|
_syscall2 (int, setrlimit, int, resource, const struct rlimit *, rlim)
|
|
_syscall2 (int, getrlimit, int, resource, struct rlimit *, rlim)
|
|
_syscall3 (int, sigaction, int signum, const struct sigaction *, act,
|
|
struct sigaction *, oldact)
|
|
_syscall0 (uid_t, getuid)
|
|
_syscall0 (gid_t, getgid)
|
|
_syscall0 (uid_t, geteuid)
|
|
_syscall0 (gid_t, getegid)
|
|
_syscall2 (int, kill, pid_t, pid, int, sig)
|
|
_syscall3 (_ssize_t, readlink, const char *, path, char *, buf, size_t, bufsize)
|
|
#endif
|