RISC-V: Moved syscalls to separate files to fix aliasing problems.
This commit is contained in:
parent
347b083911
commit
28d5b98038
|
@ -6,8 +6,39 @@ gloss_hdrs = \
|
||||||
machine/syscall.h \
|
machine/syscall.h \
|
||||||
|
|
||||||
gloss_srcs = \
|
gloss_srcs = \
|
||||||
syscalls.c \
|
nanosleep.c \
|
||||||
nanosleep.c
|
sys_access.c \
|
||||||
|
sys_chdir.c \
|
||||||
|
sys_chmod.c \
|
||||||
|
sys_chown.c \
|
||||||
|
sys_close.c \
|
||||||
|
sys_conv_stat.c \
|
||||||
|
sys_execve.c \
|
||||||
|
sys_exit.c \
|
||||||
|
sys_faccessat.c \
|
||||||
|
sys_fork.c \
|
||||||
|
sys_fstatat.c \
|
||||||
|
sys_fstat.c \
|
||||||
|
sys_ftime.c \
|
||||||
|
sys_getcwd.c \
|
||||||
|
sys_getpid.c \
|
||||||
|
sys_gettimeofday.c \
|
||||||
|
sys_isatty.c \
|
||||||
|
sys_kill.c \
|
||||||
|
sys_link.c \
|
||||||
|
sys_lseek.c \
|
||||||
|
sys_lstat.c \
|
||||||
|
sys_openat.c \
|
||||||
|
sys_open.c \
|
||||||
|
sys_read.c \
|
||||||
|
sys_sbrk.c \
|
||||||
|
sys_stat.c \
|
||||||
|
sys_sysconf.c \
|
||||||
|
sys_times.c \
|
||||||
|
sys_unlink.c \
|
||||||
|
sys_utime.c \
|
||||||
|
sys_wait.c \
|
||||||
|
sys_write.c
|
||||||
|
|
||||||
# Extra files
|
# Extra files
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
/* Copyright (c) 2017 SiFive Inc. All rights reserved.
|
||||||
|
|
||||||
|
This copyrighted material is made available to anyone wishing to use,
|
||||||
|
modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
of the FreeBSD License. This program is distributed in the hope that
|
||||||
|
it will be useful, but WITHOUT ANY WARRANTY expressed or implied,
|
||||||
|
including the implied warranties of MERCHANTABILITY or FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE. A copy of this license is available at
|
||||||
|
http://www.opensource.org/licenses.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _INTERNAL_SYSCALL_H
|
||||||
|
#define _INTERNAL_SYSCALL_H
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
static inline long
|
||||||
|
__syscall_error(long a0)
|
||||||
|
{
|
||||||
|
errno = -a0;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline long
|
||||||
|
__internal_syscall(long n, long _a0, long _a1, long _a2, long _a3, long _a4, long _a5)
|
||||||
|
{
|
||||||
|
register long a0 asm("a0") = _a0;
|
||||||
|
register long a1 asm("a1") = _a1;
|
||||||
|
register long a2 asm("a2") = _a2;
|
||||||
|
register long a3 asm("a3") = _a3;
|
||||||
|
register long a4 asm("a4") = _a4;
|
||||||
|
register long a5 asm("a5") = _a5;
|
||||||
|
|
||||||
|
#ifdef __riscv_32e
|
||||||
|
register long syscall_id asm("t0") = n;
|
||||||
|
#else
|
||||||
|
register long syscall_id asm("a7") = n;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
asm volatile ("scall"
|
||||||
|
: "+r"(a0) : "r"(a1), "r"(a2), "r"(a3), "r"(a4), "r"(a5), "r"(syscall_id));
|
||||||
|
|
||||||
|
if (a0 < 0)
|
||||||
|
return __syscall_error (a0);
|
||||||
|
else
|
||||||
|
return a0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define syscall_errno(n, a, b, c, d, e, f) \
|
||||||
|
__internal_syscall(n, (long)(a), (long)(b), (long)(c), (long)(d), (long)(e), (long)(f))
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,39 @@
|
||||||
|
/* Copyright (c) 2017 SiFive Inc. All rights reserved.
|
||||||
|
|
||||||
|
This copyrighted material is made available to anyone wishing to use,
|
||||||
|
modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
of the FreeBSD License. This program is distributed in the hope that
|
||||||
|
it will be useful, but WITHOUT ANY WARRANTY expressed or implied,
|
||||||
|
including the implied warranties of MERCHANTABILITY or FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE. A copy of this license is available at
|
||||||
|
http://www.opensource.org/licenses.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _RISCV_KERNEL_STAT_H
|
||||||
|
#define _RISCV_KERNEL_STAT_H
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
struct kernel_stat
|
||||||
|
{
|
||||||
|
unsigned long long st_dev;
|
||||||
|
unsigned long long st_ino;
|
||||||
|
unsigned int st_mode;
|
||||||
|
unsigned int st_nlink;
|
||||||
|
unsigned int st_uid;
|
||||||
|
unsigned int st_gid;
|
||||||
|
unsigned long long st_rdev;
|
||||||
|
unsigned long long __pad1;
|
||||||
|
long long st_size;
|
||||||
|
int st_blksize;
|
||||||
|
int __pad2;
|
||||||
|
long long st_blocks;
|
||||||
|
struct timespec st_atim;
|
||||||
|
struct timespec st_mtim;
|
||||||
|
struct timespec st_ctim;
|
||||||
|
int __glibc_reserved[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
void _conv_stat (struct stat *, struct kernel_stat *);
|
||||||
|
#endif /* _RISCV_KERNEL_STAT_H */
|
|
@ -54,31 +54,4 @@
|
||||||
#define SYS_time 1062
|
#define SYS_time 1062
|
||||||
#define SYS_getmainvars 2011
|
#define SYS_getmainvars 2011
|
||||||
|
|
||||||
extern long __syscall_error(long);
|
|
||||||
|
|
||||||
static inline long
|
|
||||||
__internal_syscall(long n, long _a0, long _a1, long _a2, long _a3, long _a4, long _a5)
|
|
||||||
{
|
|
||||||
register long a0 asm("a0") = _a0;
|
|
||||||
register long a1 asm("a1") = _a1;
|
|
||||||
register long a2 asm("a2") = _a2;
|
|
||||||
register long a3 asm("a3") = _a3;
|
|
||||||
register long a4 asm("a4") = _a4;
|
|
||||||
register long a5 asm("a5") = _a5;
|
|
||||||
|
|
||||||
#ifdef __riscv_32e
|
|
||||||
register long syscall_id asm("t0") = n;
|
|
||||||
#else
|
|
||||||
register long syscall_id asm("a7") = n;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
asm volatile ("scall"
|
|
||||||
: "+r"(a0) : "r"(a1), "r"(a2), "r"(a3), "r"(a4), "r"(a5), "r"(syscall_id));
|
|
||||||
|
|
||||||
if (a0 < 0)
|
|
||||||
return __syscall_error (a0);
|
|
||||||
else
|
|
||||||
return a0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
#include <machine/syscall.h>
|
||||||
|
#include "internal_syscall.h"
|
||||||
|
|
||||||
|
/* Permissions of a file (by name). */
|
||||||
|
int
|
||||||
|
_access(const char *file, int mode)
|
||||||
|
{
|
||||||
|
return syscall_errno (SYS_access, file, mode, 0, 0, 0, 0);
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
#include <machine/syscall.h>
|
||||||
|
|
||||||
|
/* Stub. */
|
||||||
|
int
|
||||||
|
_chdir(const char *path)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
#include <machine/syscall.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
/* Stub. */
|
||||||
|
int
|
||||||
|
_chmod(const char *path, mode_t mode)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
#include <machine/syscall.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
/* Stub. */
|
||||||
|
int _chown(const char *path, uid_t owner, gid_t group)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
#include <machine/syscall.h>
|
||||||
|
#include "internal_syscall.h"
|
||||||
|
|
||||||
|
/* Close a file. */
|
||||||
|
int
|
||||||
|
_close(int file)
|
||||||
|
{
|
||||||
|
return syscall_errno (SYS_close, file, 0, 0, 0, 0, 0);
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
#include <machine/syscall.h>
|
||||||
|
#include "kernel_stat.h"
|
||||||
|
|
||||||
|
/* Convert linux's stat64 sturct to newlib's stat. */
|
||||||
|
void
|
||||||
|
_conv_stat (struct stat *st, struct kernel_stat *kst)
|
||||||
|
{
|
||||||
|
st->st_dev = kst->st_dev;
|
||||||
|
st->st_ino = kst->st_ino;
|
||||||
|
st->st_mode = kst->st_mode;
|
||||||
|
st->st_nlink = kst->st_nlink;
|
||||||
|
st->st_uid = kst->st_uid;
|
||||||
|
st->st_gid = kst->st_gid;
|
||||||
|
st->st_rdev = kst->st_rdev;
|
||||||
|
st->st_size = kst->st_size;
|
||||||
|
st->st_blocks = kst->st_blocks;
|
||||||
|
st->st_blksize = kst->st_blksize;
|
||||||
|
st->st_atime = kst->st_atim.tv_sec;
|
||||||
|
st->st_mtime = kst->st_mtim.tv_sec;
|
||||||
|
st->st_ctime = kst->st_ctim.tv_sec;
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
#include <machine/syscall.h>
|
||||||
|
#include "internal_syscall.h"
|
||||||
|
|
||||||
|
/* Transfer control to a new process. Minimal implementation for a
|
||||||
|
system without processes from newlib documentation. */
|
||||||
|
int
|
||||||
|
_execve(const char *name, char *const argv[], char *const env[])
|
||||||
|
{
|
||||||
|
errno = ENOMEM;
|
||||||
|
return -1;
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
#include <machine/syscall.h>
|
||||||
|
#include "internal_syscall.h"
|
||||||
|
|
||||||
|
/* Exit a program without cleaning up files. */
|
||||||
|
void
|
||||||
|
_exit(int exit_status)
|
||||||
|
{
|
||||||
|
syscall_errno (SYS_exit, exit_status, 0, 0, 0, 0, 0);
|
||||||
|
while (1);
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
#include <machine/syscall.h>
|
||||||
|
#include "internal_syscall.h"
|
||||||
|
|
||||||
|
/* Permissions of a file (by name) in a given directory. */
|
||||||
|
int _faccessat(int dirfd, const char *file, int mode, int flags)
|
||||||
|
{
|
||||||
|
return syscall_errno (SYS_faccessat, dirfd, file, mode, flags, 0, 0);
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
#include <machine/syscall.h>
|
||||||
|
#include "internal_syscall.h"
|
||||||
|
|
||||||
|
/* Create a new process. Minimal implementation for a system without
|
||||||
|
processes from newlib documentation. */
|
||||||
|
int _fork()
|
||||||
|
{
|
||||||
|
errno = EAGAIN;
|
||||||
|
return -1;
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
#include <machine/syscall.h>
|
||||||
|
#include "kernel_stat.h"
|
||||||
|
#include "internal_syscall.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)
|
||||||
|
{
|
||||||
|
struct kernel_stat kst;
|
||||||
|
int rv = syscall_errno (SYS_fstat, file, &kst, 0, 0, 0, 0);
|
||||||
|
_conv_stat (st, &kst);
|
||||||
|
return rv;
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
#include <machine/syscall.h>
|
||||||
|
#include "kernel_stat.h"
|
||||||
|
#include "internal_syscall.h"
|
||||||
|
|
||||||
|
/* Status of an open file. The sys/stat.h header file required is
|
||||||
|
distributed in the include subdirectory for this C library. */
|
||||||
|
int
|
||||||
|
_fstatat(int dirfd, const char *file, struct stat *st, int flags)
|
||||||
|
{
|
||||||
|
struct kernel_stat kst;
|
||||||
|
int rv = syscall_errno (SYS_fstatat, dirfd, file, &kst, flags, 0, 0);
|
||||||
|
_conv_stat (st, &kst);
|
||||||
|
return rv;
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
#include <machine/syscall.h>
|
||||||
|
#include <sys/timeb.h>
|
||||||
|
|
||||||
|
/* Get the current time. Only relatively correct. */
|
||||||
|
int
|
||||||
|
_ftime(struct timeb *tp)
|
||||||
|
{
|
||||||
|
tp->time = tp->millitm = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
#include <machine/syscall.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
/* Stub. */
|
||||||
|
char *
|
||||||
|
_getcwd(char *buf, size_t size)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
#include <machine/syscall.h>
|
||||||
|
|
||||||
|
/* Get process id. This is sometimes used to generate strings unlikely
|
||||||
|
to conflict with other processes. Minimal implementation for a
|
||||||
|
system without processes just returns 1. */
|
||||||
|
|
||||||
|
int
|
||||||
|
_getpid()
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
#include <machine/syscall.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include "internal_syscall.h"
|
||||||
|
|
||||||
|
/* Get the current time. Only relatively correct. */
|
||||||
|
int
|
||||||
|
_gettimeofday(struct timeval *tp, void *tzp)
|
||||||
|
{
|
||||||
|
return syscall_errno (SYS_gettimeofday, tp, 0, 0, 0, 0, 0);
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
#include <machine/syscall.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include "internal_syscall.h"
|
||||||
|
|
||||||
|
extern int _fstat(int file, struct stat *st);
|
||||||
|
|
||||||
|
/* Query whether output stream is a terminal. For consistency with the
|
||||||
|
other minimal implementations, which only support output to stdout,
|
||||||
|
this minimal implementation is suggested by the newlib docs. */
|
||||||
|
|
||||||
|
int
|
||||||
|
_isatty(int file)
|
||||||
|
{
|
||||||
|
struct stat s;
|
||||||
|
int ret = _fstat (file, &s);
|
||||||
|
return ret == -1 ? -1 : !!(s.st_mode & S_IFCHR);
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
#include <machine/syscall.h>
|
||||||
|
#include "internal_syscall.h"
|
||||||
|
|
||||||
|
/* Send a signal. Minimal implementation for a system without processes
|
||||||
|
just causes an error. */
|
||||||
|
int
|
||||||
|
_kill(int pid, int sig)
|
||||||
|
{
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
#include <machine/syscall.h>
|
||||||
|
#include "internal_syscall.h"
|
||||||
|
|
||||||
|
/* Establish a new name for an existing file. */
|
||||||
|
int _link(const char *old_name, const char *new_name)
|
||||||
|
{
|
||||||
|
return syscall_errno (SYS_link, old_name, new_name, 0, 0, 0, 0);
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
#include <machine/syscall.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include "internal_syscall.h"
|
||||||
|
|
||||||
|
/* Set position in a file. */
|
||||||
|
off_t
|
||||||
|
_lseek(int file, off_t ptr, int dir)
|
||||||
|
{
|
||||||
|
return syscall_errno (SYS_lseek, file, ptr, dir, 0, 0, 0);
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
#include <machine/syscall.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include "internal_syscall.h"
|
||||||
|
#include "kernel_stat.h"
|
||||||
|
|
||||||
|
/* Status of a link (by name). */
|
||||||
|
int _lstat(const char *file, struct stat *st)
|
||||||
|
{
|
||||||
|
struct kernel_stat kst;
|
||||||
|
int rv = syscall_errno (SYS_lstat, file, &kst, 0, 0, 0, 0);
|
||||||
|
_conv_stat (st, &kst);
|
||||||
|
return rv;
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
#include <machine/syscall.h>
|
||||||
|
#include "internal_syscall.h"
|
||||||
|
|
||||||
|
/* Open a file. */
|
||||||
|
int
|
||||||
|
_open(const char *name, int flags, int mode)
|
||||||
|
{
|
||||||
|
return syscall_errno (SYS_open, name, flags, mode, 0, 0, 0);
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
#include <machine/syscall.h>
|
||||||
|
#include "internal_syscall.h"
|
||||||
|
|
||||||
|
/* Open file relative to given directory. */
|
||||||
|
int _openat(int dirfd, const char *name, int flags, int mode)
|
||||||
|
{
|
||||||
|
return syscall_errno (SYS_openat, dirfd, name, flags, mode, 0, 0);
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
#include <machine/syscall.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include "internal_syscall.h"
|
||||||
|
|
||||||
|
/* Read from a file. */
|
||||||
|
ssize_t _read(int file, void *ptr, size_t len)
|
||||||
|
{
|
||||||
|
return syscall_errno (SYS_read, file, ptr, len, 0, 0, 0);
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
#include <machine/syscall.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include "internal_syscall.h"
|
||||||
|
|
||||||
|
/* Increase program data space. As malloc and related functions depend
|
||||||
|
on this, it is useful to have a working implementation. The following
|
||||||
|
is suggested by the newlib docs and suffices for a standalone
|
||||||
|
system. */
|
||||||
|
void *
|
||||||
|
_sbrk(ptrdiff_t incr)
|
||||||
|
{
|
||||||
|
static unsigned long heap_end;
|
||||||
|
|
||||||
|
if (heap_end == 0)
|
||||||
|
{
|
||||||
|
long brk = syscall_errno (SYS_brk, 0, 0, 0, 0, 0, 0);
|
||||||
|
if (brk == -1)
|
||||||
|
return (void *)-1;
|
||||||
|
heap_end = brk;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (syscall_errno (SYS_brk, heap_end + incr, 0, 0, 0, 0, 0) != heap_end + incr)
|
||||||
|
return (void *)-1;
|
||||||
|
|
||||||
|
heap_end += incr;
|
||||||
|
return (void *)(heap_end - incr);
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
#include <machine/syscall.h>
|
||||||
|
#include "kernel_stat.h"
|
||||||
|
#include "internal_syscall.h"
|
||||||
|
|
||||||
|
/* Status of a file (by name). */
|
||||||
|
|
||||||
|
int
|
||||||
|
_stat(const char *file, struct stat *st)
|
||||||
|
{
|
||||||
|
struct kernel_stat kst;
|
||||||
|
int rv = syscall_errno (SYS_stat, file, &kst, 0, 0, 0, 0);
|
||||||
|
_conv_stat (st, &kst);
|
||||||
|
return rv;
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
#include <machine/syscall.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
/* Get configurable system variables. */
|
||||||
|
|
||||||
|
long
|
||||||
|
_sysconf(int name)
|
||||||
|
{
|
||||||
|
switch (name)
|
||||||
|
{
|
||||||
|
case _SC_CLK_TCK:
|
||||||
|
return CLOCKS_PER_SEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
#include <machine/syscall.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/times.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include "internal_syscall.h"
|
||||||
|
|
||||||
|
extern int _gettimeofday(struct timeval *, void *);
|
||||||
|
|
||||||
|
/* Timing information for current process. From
|
||||||
|
newlib/libc/include/sys/times.h the tms struct fields are as follows:
|
||||||
|
|
||||||
|
- clock_t tms_utime : user clock ticks
|
||||||
|
- clock_t tms_stime : system clock ticks
|
||||||
|
- clock_t tms_cutime : children's user clock ticks
|
||||||
|
- clock_t tms_cstime : children's system clock ticks
|
||||||
|
|
||||||
|
Since maven does not currently support processes we set both of the
|
||||||
|
children's times to zero. Eventually we might want to separately
|
||||||
|
account for user vs system time, but for now we just return the total
|
||||||
|
number of cycles since starting the program. */
|
||||||
|
clock_t
|
||||||
|
_times(struct tms *buf)
|
||||||
|
{
|
||||||
|
// when called for the first time, initialize t0
|
||||||
|
static struct timeval t0;
|
||||||
|
if (t0.tv_sec == 0)
|
||||||
|
_gettimeofday (&t0, 0);
|
||||||
|
|
||||||
|
struct timeval t;
|
||||||
|
_gettimeofday (&t, 0);
|
||||||
|
|
||||||
|
long long utime = (t.tv_sec - t0.tv_sec) * 1000000 + (t.tv_usec - t0.tv_usec);
|
||||||
|
buf->tms_utime = utime * CLOCKS_PER_SEC / 1000000;
|
||||||
|
buf->tms_stime = buf->tms_cstime = buf->tms_cutime = 0;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
#include <machine/syscall.h>
|
||||||
|
#include "internal_syscall.h"
|
||||||
|
|
||||||
|
/* Remove a file's directory entry. */
|
||||||
|
int
|
||||||
|
_unlink(const char *name)
|
||||||
|
{
|
||||||
|
return syscall_errno (SYS_unlink, name, 0, 0, 0, 0, 0);
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
#include <machine/syscall.h>
|
||||||
|
|
||||||
|
/* Stub. */
|
||||||
|
int
|
||||||
|
_utime(const char *path, const struct utimbuf *times)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
#include <machine/syscall.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
/* Wait for a child process. Minimal implementation for a system without
|
||||||
|
processes just causes an error. */
|
||||||
|
int _wait(int *status)
|
||||||
|
{
|
||||||
|
errno = ECHILD;
|
||||||
|
return -1;
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
#include <machine/syscall.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include "internal_syscall.h"
|
||||||
|
|
||||||
|
/* Write to a file. */
|
||||||
|
ssize_t
|
||||||
|
_write(int file, const void *ptr, size_t len)
|
||||||
|
{
|
||||||
|
return syscall_errno (SYS_write, file, ptr, len, 0, 0, 0);
|
||||||
|
}
|
|
@ -1,421 +0,0 @@
|
||||||
/* Copyright (c) 2017 SiFive Inc. All rights reserved.
|
|
||||||
|
|
||||||
This copyrighted material is made available to anyone wishing to use,
|
|
||||||
modify, copy, or redistribute it subject to the terms and conditions
|
|
||||||
of the FreeBSD License. This program is distributed in the hope that
|
|
||||||
it will be useful, but WITHOUT ANY WARRANTY expressed or implied,
|
|
||||||
including the implied warranties of MERCHANTABILITY or FITNESS FOR
|
|
||||||
A PARTICULAR PURPOSE. A copy of this license is available at
|
|
||||||
http://www.opensource.org/licenses.
|
|
||||||
|
|
||||||
========================================================================
|
|
||||||
syscalls.c : Newlib operating system interface
|
|
||||||
========================================================================
|
|
||||||
This is the maven implementation of the narrow newlib operating
|
|
||||||
system interface. It is based on the minimum stubs in the newlib
|
|
||||||
documentation, the error stubs in libnosys, and the previous scale
|
|
||||||
implementation. Please do not include any additional system calls or
|
|
||||||
other functions in this file. Additional header and source files
|
|
||||||
should be in the machine subdirectory.
|
|
||||||
|
|
||||||
Here is a list of the functions which make up the operating system
|
|
||||||
interface. The file management instructions execute syscall assembly
|
|
||||||
instructions so that a proxy kernel (or the simulator) can marshal up
|
|
||||||
the request to the host machine. The process management functions are
|
|
||||||
mainly just stubs since for now maven only supports a single process.
|
|
||||||
|
|
||||||
- File management functions
|
|
||||||
+ open : (v) open file
|
|
||||||
+ lseek : (v) set position in file
|
|
||||||
+ read : (v) read from file
|
|
||||||
+ write : (v) write to file
|
|
||||||
+ fstat : (z) status of an open file
|
|
||||||
+ stat : (z) status of a file by name
|
|
||||||
+ close : (z) close a file
|
|
||||||
+ link : (z) rename a file
|
|
||||||
+ unlink : (z) remote file's directory entry
|
|
||||||
|
|
||||||
- Process management functions
|
|
||||||
+ execve : (z) transfer control to new proc
|
|
||||||
+ fork : (z) create a new process
|
|
||||||
+ getpid : (v) get process id
|
|
||||||
+ kill : (z) send signal to child process
|
|
||||||
+ wait : (z) wait for a child process
|
|
||||||
|
|
||||||
- Misc functions
|
|
||||||
+ isatty : (v) query whether output stream is a terminal
|
|
||||||
+ times : (z) timing information for current process
|
|
||||||
+ sbrk : (v) increase program data space
|
|
||||||
+ _exit : (-) exit program without cleaning up files
|
|
||||||
|
|
||||||
There are two types of system calls. Those which return a value when
|
|
||||||
everything is okay (marked with (v) in above list) and those which
|
|
||||||
return a zero when everything is okay (marked with (z) in above
|
|
||||||
list). On an error (ie. when the error flag is 1) the return value is
|
|
||||||
always an errno which should correspond to the numbers in
|
|
||||||
newlib/libc/include/sys/errno.h
|
|
||||||
|
|
||||||
See the newlib documentation for more information
|
|
||||||
http://sourceware.org/newlib/libc.html#Syscalls
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <machine/syscall.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <sys/times.h>
|
|
||||||
#include <sys/time.h>
|
|
||||||
#include <sys/timeb.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <utime.h>
|
|
||||||
|
|
||||||
#define syscall_errno(n, a, b, c, d, e, f) \
|
|
||||||
__internal_syscall(n, (long)(a), (long)(b), (long)(c), \
|
|
||||||
(long)(d), (long)(e), (long)(f))
|
|
||||||
|
|
||||||
long
|
|
||||||
__syscall_error(long a0)
|
|
||||||
{
|
|
||||||
errno = -a0;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Open a file. */
|
|
||||||
int
|
|
||||||
_open(const char *name, int flags, int mode)
|
|
||||||
{
|
|
||||||
return syscall_errno (SYS_open, name, flags, mode, 0, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Open file relative to given directory. */
|
|
||||||
int
|
|
||||||
_openat(int dirfd, const char *name, int flags, int mode)
|
|
||||||
{
|
|
||||||
return syscall_errno (SYS_openat, dirfd, name, flags, mode, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set position in a file. */
|
|
||||||
off_t
|
|
||||||
_lseek(int file, off_t ptr, int dir)
|
|
||||||
{
|
|
||||||
return syscall_errno (SYS_lseek, file, ptr, dir, 0, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Read from a file. */
|
|
||||||
ssize_t
|
|
||||||
_read(int file, void *ptr, size_t len)
|
|
||||||
{
|
|
||||||
return syscall_errno (SYS_read, file, ptr, len, 0, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Write to a file. */
|
|
||||||
ssize_t
|
|
||||||
_write(int file, const void *ptr, size_t len)
|
|
||||||
{
|
|
||||||
return syscall_errno (SYS_write, file, ptr, len, 0, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct kernel_stat
|
|
||||||
{
|
|
||||||
unsigned long long st_dev;
|
|
||||||
unsigned long long st_ino;
|
|
||||||
unsigned int st_mode;
|
|
||||||
unsigned int st_nlink;
|
|
||||||
unsigned int st_uid;
|
|
||||||
unsigned int st_gid;
|
|
||||||
unsigned long long st_rdev;
|
|
||||||
unsigned long long __pad1;
|
|
||||||
long long st_size;
|
|
||||||
int st_blksize;
|
|
||||||
int __pad2;
|
|
||||||
long long st_blocks;
|
|
||||||
struct timespec st_atim;
|
|
||||||
struct timespec st_mtim;
|
|
||||||
struct timespec st_ctim;
|
|
||||||
int __glibc_reserved[2];
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Convert linux's stat64 sturct to newlib's stat. */
|
|
||||||
static void
|
|
||||||
conv_stat (struct stat *st, struct kernel_stat *kst)
|
|
||||||
{
|
|
||||||
st->st_dev = kst->st_dev;
|
|
||||||
st->st_ino = kst->st_ino;
|
|
||||||
st->st_mode = kst->st_mode;
|
|
||||||
st->st_nlink = kst->st_nlink;
|
|
||||||
st->st_uid = kst->st_uid;
|
|
||||||
st->st_gid = kst->st_gid;
|
|
||||||
st->st_rdev = kst->st_rdev;
|
|
||||||
st->st_size = kst->st_size;
|
|
||||||
st->st_blocks = kst->st_blocks;
|
|
||||||
st->st_blksize = kst->st_blksize;
|
|
||||||
st->st_atime = kst->st_atim.tv_sec;
|
|
||||||
st->st_mtime = kst->st_mtim.tv_sec;
|
|
||||||
st->st_ctime = kst->st_ctim.tv_sec;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 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)
|
|
||||||
{
|
|
||||||
struct kernel_stat kst;
|
|
||||||
int rv = syscall_errno (SYS_fstat, file, &kst, 0, 0, 0, 0);
|
|
||||||
conv_stat (st, &kst);
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Status of a file (by name). */
|
|
||||||
int
|
|
||||||
_stat(const char *file, struct stat *st)
|
|
||||||
{
|
|
||||||
struct kernel_stat kst;
|
|
||||||
int rv = syscall_errno (SYS_stat, file, &kst, 0, 0, 0, 0);
|
|
||||||
conv_stat (st, &kst);
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Status of a link (by name). */
|
|
||||||
int
|
|
||||||
_lstat(const char *file, struct stat *st)
|
|
||||||
{
|
|
||||||
struct kernel_stat kst;
|
|
||||||
int rv = syscall_errno (SYS_lstat, file, &kst, 0, 0, 0, 0);
|
|
||||||
conv_stat (st, &kst);
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Status of a file (by name) in a given directory. */
|
|
||||||
int
|
|
||||||
_fstatat(int dirfd, const char *file, struct stat *st, int flags)
|
|
||||||
{
|
|
||||||
struct kernel_stat kst;
|
|
||||||
int rv = syscall_errno (SYS_fstatat, dirfd, file, &kst, flags, 0, 0);
|
|
||||||
conv_stat (st, &kst);
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Permissions of a file (by name). */
|
|
||||||
int
|
|
||||||
_access(const char *file, int mode)
|
|
||||||
{
|
|
||||||
return syscall_errno (SYS_access, file, mode, 0, 0, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Permissions of a file (by name) in a given directory. */
|
|
||||||
int
|
|
||||||
_faccessat(int dirfd, const char *file, int mode, int flags)
|
|
||||||
{
|
|
||||||
return syscall_errno (SYS_faccessat, dirfd, file, mode, flags, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Close a file. */
|
|
||||||
int
|
|
||||||
_close(int file)
|
|
||||||
{
|
|
||||||
return syscall_errno (SYS_close, file, 0, 0, 0, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Establish a new name for an existing file. */
|
|
||||||
int
|
|
||||||
_link(const char *old_name, const char *new_name)
|
|
||||||
{
|
|
||||||
return syscall_errno (SYS_link, old_name, new_name, 0, 0, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Remove a file's directory entry. */
|
|
||||||
int
|
|
||||||
_unlink(const char *name)
|
|
||||||
{
|
|
||||||
return syscall_errno (SYS_unlink, name, 0, 0, 0, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Transfer control to a new process. Minimal implementation for a
|
|
||||||
system without processes from newlib documentation. */
|
|
||||||
int
|
|
||||||
_execve(const char *name, char *const argv[], char *const env[])
|
|
||||||
{
|
|
||||||
errno = ENOMEM;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Create a new process. Minimal implementation for a system without
|
|
||||||
processes from newlib documentation. */
|
|
||||||
|
|
||||||
int
|
|
||||||
_fork()
|
|
||||||
{
|
|
||||||
errno = EAGAIN;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get process id. This is sometimes used to generate strings unlikely
|
|
||||||
to conflict with other processes. Minimal implementation for a
|
|
||||||
system without processes just returns 1. */
|
|
||||||
|
|
||||||
int
|
|
||||||
_getpid()
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Send a signal. Minimal implementation for a system without processes
|
|
||||||
just causes an error. */
|
|
||||||
|
|
||||||
int
|
|
||||||
_kill(int pid, int sig)
|
|
||||||
{
|
|
||||||
errno = EINVAL;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Wait for a child process. Minimal implementation for a system without
|
|
||||||
processes just causes an error. */
|
|
||||||
|
|
||||||
int
|
|
||||||
_wait(int *status)
|
|
||||||
{
|
|
||||||
errno = ECHILD;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Query whether output stream is a terminal. For consistency with the
|
|
||||||
other minimal implementations, which only support output to stdout,
|
|
||||||
this minimal implementation is suggested by the newlib docs. */
|
|
||||||
|
|
||||||
int
|
|
||||||
_isatty(int file)
|
|
||||||
{
|
|
||||||
struct stat s;
|
|
||||||
int ret = _fstat (file, &s);
|
|
||||||
return ret == -1 ? -1 : !!(s.st_mode & S_IFCHR);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get the current time. Only relatively correct. */
|
|
||||||
|
|
||||||
int
|
|
||||||
_gettimeofday(struct timeval *tp, void *tz)
|
|
||||||
{
|
|
||||||
return syscall_errno (SYS_gettimeofday, tp, 0, 0, 0, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Timing information for current process. From
|
|
||||||
newlib/libc/include/sys/times.h the tms struct fields are as follows:
|
|
||||||
|
|
||||||
- clock_t tms_utime : user clock ticks
|
|
||||||
- clock_t tms_stime : system clock ticks
|
|
||||||
- clock_t tms_cutime : children's user clock ticks
|
|
||||||
- clock_t tms_cstime : children's system clock ticks
|
|
||||||
|
|
||||||
Since maven does not currently support processes we set both of the
|
|
||||||
children's times to zero. Eventually we might want to separately
|
|
||||||
account for user vs system time, but for now we just return the total
|
|
||||||
number of cycles since starting the program. */
|
|
||||||
clock_t
|
|
||||||
_times(struct tms *buf)
|
|
||||||
{
|
|
||||||
// when called for the first time, initialize t0
|
|
||||||
static struct timeval t0;
|
|
||||||
if(t0.tv_sec == 0)
|
|
||||||
_gettimeofday (&t0,0);
|
|
||||||
|
|
||||||
struct timeval t;
|
|
||||||
_gettimeofday (&t, 0);
|
|
||||||
|
|
||||||
long long utime = (t.tv_sec - t0.tv_sec) * 1000000 + (t.tv_usec - t0.tv_usec);
|
|
||||||
buf->tms_utime = utime * CLOCKS_PER_SEC / 1000000;
|
|
||||||
buf->tms_stime = buf->tms_cstime = buf->tms_cutime = 0;
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get the current time. Only relatively correct. */
|
|
||||||
int
|
|
||||||
_ftime(struct timeb *tp)
|
|
||||||
{
|
|
||||||
tp->time = tp->millitm = 0;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Stub. */
|
|
||||||
int
|
|
||||||
_utime(const char *path, const struct utimbuf *times)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Stub. */
|
|
||||||
int
|
|
||||||
_chown(const char *path, uid_t owner, gid_t group)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Stub. */
|
|
||||||
int
|
|
||||||
_chmod(const char *path, mode_t mode)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Stub. */
|
|
||||||
int
|
|
||||||
_chdir(const char *path)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Stub. */
|
|
||||||
char *
|
|
||||||
_getcwd(char *buf, size_t size)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get configurable system variables. */
|
|
||||||
|
|
||||||
long
|
|
||||||
_sysconf(int name)
|
|
||||||
{
|
|
||||||
switch (name)
|
|
||||||
{
|
|
||||||
case _SC_CLK_TCK:
|
|
||||||
return CLOCKS_PER_SEC;
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Increase program data space. As malloc and related functions depend
|
|
||||||
on this, it is useful to have a working implementation. The following
|
|
||||||
is suggested by the newlib docs and suffices for a standalone
|
|
||||||
system. */
|
|
||||||
void *
|
|
||||||
_sbrk(ptrdiff_t incr)
|
|
||||||
{
|
|
||||||
static unsigned long heap_end;
|
|
||||||
|
|
||||||
if (heap_end == 0)
|
|
||||||
{
|
|
||||||
long brk = syscall_errno (SYS_brk, 0, 0, 0, 0, 0, 0);
|
|
||||||
if (brk == -1)
|
|
||||||
return (void *)-1;
|
|
||||||
heap_end = brk;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (syscall_errno (SYS_brk, heap_end + incr, 0, 0, 0, 0, 0)
|
|
||||||
!= heap_end + incr)
|
|
||||||
return (void *)-1;
|
|
||||||
|
|
||||||
heap_end += incr;
|
|
||||||
return (void *)(heap_end - incr);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Exit a program without cleaning up files. */
|
|
||||||
|
|
||||||
void
|
|
||||||
_exit(int exit_status)
|
|
||||||
{
|
|
||||||
syscall_errno (SYS_exit, exit_status, 0, 0, 0, 0, 0);
|
|
||||||
while (1);
|
|
||||||
}
|
|
Loading…
Reference in New Issue