$NetBSD: patch-ao,v 1.1.1.1 2011/07/27 10:23:50 cherry Exp $ --- src/netbsd/syscall-netbsd.c.orig 2010-06-09 19:58:06.000000000 +0530 +++ src/netbsd/syscall-netbsd.c @@ -0,0 +1,662 @@ +/* + * Copyright (C) 1995-2007, Hewlett-Packard Development Company, L.P. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +/* + * Note: We provide binary support only for NetBSD here. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "std.h" +#include "types.h" +#include "sim.h" +#include "state.h" +#include "simmem.h" +#include "libsrs.h" +#include "libcore.h" +#include "os_support.h" + +#include "netbsd/machdep-netbsd.h" +#include "netbsd/signal-netbsd.h" +#include "netbsd/syscall-netbsd.h" + +#define NBSD_PAGESIZE 16384 +#define NBSD_PAGEMASK (NBSD_PAGESIZE-1) + +/* Arbitrary... */ +#define NBSD_MMAP_START 0x6000000100000000ULL +#define NBSD_MMAP_END 0x7FFFFFFFFFFFFFFFULL + +#define nbsd_trunc_page(x) ((ADDR)(x) & ~NBSD_PAGEMASK) +#define nbsd_round_page(x) nbsd_trunc_page((x) + NBSD_PAGEMASK) + +void memFree(ADDR adr); +BOOL pmemMap(ADDR adr, void *hostadr); + +extern int fdlimit; + +int _close(int); +int _open(const char *, int, int); + +BOOL trace_syscalls = NO; +char *consLog = NULL; + +static ADDR mmap_base = NBSD_MMAP_START; + +static void * +unmap_mapped_pages(ADDR base, REG size) +{ + ADDR addr, end; + void *res; + + /* We expect page aligned addresses here. */ + assert((base & NBSD_PAGEMASK) == 0); + + end = nbsd_round_page(base + size); + res = pmemLookup(base); + for (addr = base; addr < end; addr += page_size) { + if (pmemLookup(addr) == NULL) + continue; + memFree(addr); + } + return res; +} + +static ADDR +verify_unmapped_pages(ADDR base, REG size) +{ + ADDR addr, end; + + /* We expect page aligned addresses here. */ + assert((base & NBSD_PAGEMASK) == 0); + + end = nbsd_round_page(base + size); + for (addr = base; addr < end; addr += page_size) { + if (pmemLookup(addr) != NULL) + return 0; + } + return base; +} + +static ADDR +get_unmapped_pages(REG size) +{ + ADDR start; + + while (mmap_base <= NBSD_MMAP_END) { + start = verify_unmapped_pages(mmap_base, size); + if (start != 0) { + mmap_base = nbsd_round_page(mmap_base + size); + return start; + } + mmap_base += NBSD_PAGESIZE; + } + return 0ULL; +} + +static int +nbsd_ioctl(int fd, unsigned long com, REG data) +{ + void *buf; + size_t len; + int res; + + len = IOCPARM_LEN(com); + if (len > NBSD_PAGESIZE) { + errno = ENOTTY; + return -1; + } + if (len) + buf = alloca(len); + else + buf = (void*)(intptr_t)data; + if ((com & IOC_IN) && len) + memBBRd(data, buf, len); + res = ioctl(fd, com, buf); + if ((com & IOC_OUT) && len) + memBBWrt_alloc(data, buf, len); + return res; +} + +void doSyscall(HWORD num, REG arg0, REG arg1, REG arg2, REG arg3, REG arg4, + REG arg5, REG arg6, REG arg7, REG *ret, REG *status) +{ + int res = -1; + + *status = 0; + + /* syscalls and user space support not available for NetBSD */ + ret = ENOSYS; + goto out; + +#if 0 + if (num == SYS___syscall) { + num = arg0; + arg0 = arg1; + arg1 = arg2; + arg2 = arg3; + arg3 = arg4; + arg4 = arg5; + arg5 = arg6; + arg6 = arg7; + } + +#if 0 + printf("syscall %d", num); +#endif + + switch (num) { + case SYS_exit: + /* void sys_exit(int rval); */ + GrWrtx(8, arg0, 0); + progExit("program exited with status %d\n", (int)arg0); + goto out; + case SYS_read: { + /* ssize_t read(int fd, void *buf, size_t nbyte); */ + char *buf = alloca(arg2); + res = read(arg0, buf, arg2); + if (res > 0) + memBBWrt_alloc(arg1, buf, res); + break; + } + case SYS_write: { + /* ssize_t write(int fd, const void *buf, size_t nbyte); */ + char *buf = alloca(arg2); + memBBRd(arg1, buf, arg2); + res = write(arg0, buf, arg2); + break; + } + case SYS_open: { + /* int open(char *path, int flags, int mode); */ + char path[PATH_MAX]; + simroot(arg0, path, arg1 & O_CREAT); + res = _open(path, arg1, arg2); + if (res >= fdlimit) { + _close(res); + errno = EMFILE; + res = -1; + } + break; + } + case SYS_close: + /* int close(int fd); */ + if (arg0 >= fdlimit) { + errno = EBADF; + res = -1; + } else + res = _close(arg0); + break; + case SYS_unlink: { + /* int unlink(char *path); */ + char path[PATH_MAX]; + simroot(arg0, path, 0); + res = unlink(path); + break; + } + case SYS_fchdir: + /* int fchdir(int fd); */ + res = fchdir(arg0); + break; + case SYS_break: { + /* int obreak(char *nsize); */ + REG brk = heapGet(0); + if (brk <= NBSD_MMAP_END) { + if (arg0 > brk) { + for (brk = page_base(brk); brk < arg0; + brk += page_size) + pmemLookup_p(brk); + heapSet(0, brk); + } else if (arg0 == 0) + arg0 = brk; + res = 0; + } else { + errno = EINVAL; + res = -1; + } + break; + } + case SYS_getpid: + /* pid_t getpid(void); */ + *ret = getpid(); + goto out; + case SYS_getuid: + /* uid_t getuid(void); */ + *ret = getuid(); + goto out; + case SYS_geteuid: + /* uid_t geteuid(void); */ + *ret = geteuid(); + goto out; + case SYS_access: { + /* int access(char *path, int flags); */ + char path[PATH_MAX]; + simroot(arg0, path, 0); + res = access(path, arg1); + break; + } + case SYS_chflags: { + /* int chflags(char *path, int flags); */ + char path[PATH_MAX]; + simroot(arg0, path, 0); + res = chflags(path, arg1); + break; + } + case SYS_kill: + /* int kill(int pid, int signum); */ + res = kill(arg0, arg1); + break; + case SYS_pipe: { + /* (int,int) pipe(void); */ + int fildes[2]; + res = pipe(fildes); + if (res == 0) { + GrWrtx(9, (REG)fildes[1], 0); + res = (REG)fildes[0]; + } + break; + } + case SYS_getegid: + /* gid_t getegid(void); */ + *ret = getegid(); + goto out; + case SYS_getgid: + /* gid_t getgid(void); */ + *ret = getgid(); + goto out; + case SYS_ioctl: + /* int ioctl(int fd, u_long com, caddr_t data); */ + res = nbsd_ioctl(arg0, arg1, arg2); + break; + case SYS_readlink: { + /* int readlink(char *path, char *buf, int count); */ + char *buf, path[PATH_MAX]; + size_t count; + simroot(arg0, path, 0); + count = arg2; + buf = alloca(count); + res = readlink(path, buf, count); + memBBWrt_alloc(arg1, buf, count); + break; + } + case SYS_munmap: { + /* int munmap(void *addr, size_t len); */ + caddr_t addr; + ADDR reloc; + reloc = arg0; + arg0 = nbsd_trunc_page(arg0); + reloc -= arg0; + arg1 += reloc; + addr = unmap_mapped_pages(arg0, arg1); + res = munmap(addr, arg1); + break; + } + case SYS_mprotect: { + /* int mprotect(const void *addr, size_t len, int prot); */ + ADDR reloc; + void *addr; + reloc = arg0; + arg0 = nbsd_trunc_page(arg0); + arg1 += reloc - arg0; + arg1 = nbsd_round_page(arg1); + addr = pmemLookup(arg0); + res = mprotect(addr, arg1, arg2); + break; + } + case SYS___setitimer50: { + /* int setitimer(u_int which, struct itimerval *itv, + * struct itimerval *oitv); + */ + struct itimerval itv, oitv, *itvp; + struct itimerval64 itv64; + itvp = (arg1 != 0) ? &itv : NULL; + if (arg1 != 0) { + memBBRd(arg1, (void*)&itv64, sizeof(itv64)); + ston_itimerval(&itv64, itvp); + } + res = setitimer((int)arg0, itvp, &oitv); + if (arg2 != 0) { + ntos_itimerval(&oitv, &itv64); + memBBWrt_alloc(arg2, (void*)&itv64, sizeof(itv64)); + } + break; + } + /* XXX: Fix this */ + /* case SYS_getdtablesize: */ + /* /\* int getdtablesize(void); *\/ */ + /* res = getdtablesize() - SKI_NFDS; */ + /* break; */ + case SYS_dup2: + /* int dup2(u_int from, u_int to); */ + if (arg1 >= fdlimit) { + errno = EBADF; + res = -1; + } else + res = dup2(arg0, arg1); + break; + case SYS_fcntl: { + /* int fcntl(int fd, int cmd, long arg); */ + struct flock l; + switch (arg1) { + case F_GETLK: + case F_SETLK: + case F_SETLKW: + memBBRd(arg2, (void*)&l, sizeof(l)); + res = fcntl(arg0, arg1, &l); + memBBWrt_alloc(arg2, (void*)&l, sizeof(l)); + break; + default: + res = fcntl(arg0, arg1, arg2); + break; + } + break; + } + case SYS___socket30: + /* int socket(int domain, int type, int protocol); */ + res = socket(arg0, arg1, arg2); + break; + case SYS_connect: { + /* int connect(int s, caddr_t name, int namelen); */ + void *name; + name = alloca(arg2); + memBBRd(arg1, name, arg2); + res = connect(arg0, name, arg2); + break; + } + case SYS___gettimeofday50: { + /* int gettimeofday(struct timeval *tp, + * struct timezone *tzp); + */ + struct timeval64 tp64; + struct timeval tp; + struct timezone tzp; + res = gettimeofday(&tp, &tzp); + ntos_timeval(&tp, &tp64); + if (arg0 != 0) + memBBWrt_alloc(arg0, (void*)&tp64, sizeof(tp64)); + if (arg1 != 0) + memBBWrt_alloc(arg1, (void*)&tzp, sizeof(tzp)); + break; + } + case SYS___getrusage50: { + /* int getrusage(int who, struct rusage *rusage); */ + struct rusage64 ru64; + struct rusage ru; + res = getrusage(arg0, &ru); + ntos_rusage(&ru, &ru64); + memBBWrt_alloc(arg1, (void*)&ru64, sizeof(ru64)); + break; + } + case SYS_sendto: { + /* int sendto(int s, caddr_t buf, size_t len, int flags, + * caddr_t to, int tolen); + */ + void *msg, *to; + msg = alloca(arg2); + memBBRd(arg1, msg, arg2); + to = alloca(arg5); + memBBRd(arg4, to, arg5); + res = sendto(arg0, msg, arg2, arg3, to, arg5); + break; + } + /* XXX: case SYS_compat_20_fstatfs: { */ + /* /\* int fstatfs(int fd, struct statfs *buf); *\/ */ + /* struct statfs64 buf64; */ + /* struct statfs buf; */ + /* res = fstatfs(arg0, &buf); */ + /* ntos_statfs(&buf, &buf64); */ + /* memBBWrt_alloc(arg1, (void*)&buf64, sizeof(buf64)); */ + /* break; */ + /* } */ + case SYS___stat50: { + /* int stat(char *path, struct stat *ub); */ + char path[PATH_MAX]; + struct stat64 sb64; + struct stat sb; + simroot(arg0, path, 0); + res = stat(path, &sb); + ntos_stat(&sb, &sb64); + memBBWrt_alloc(arg1, (void*)&sb64, sizeof(sb64)); + break; + } + case SYS___fstat50: { + /* int fstat(int fd, struct stat *sb); */ + struct stat64 sb64; + struct stat sb; + res = fstat(arg0, &sb); + ntos_stat(&sb, &sb64); + memBBWrt_alloc(arg1, (void*)&sb64, sizeof(sb64)); + break; + } + case SYS___lstat50: { + /* int lstat(char *path, struct stat *ub); */ + char path[PATH_MAX]; + struct stat64 sb64; + struct stat sb; + simroot(arg0, path, 0); + res = stat(path, &sb); + ntos_stat(&sb, &sb64); + memBBWrt_alloc(arg1, (void*)&sb64, sizeof(sb64)); + break; + } + case SYS_getrlimit: { + /* int getrlimit(u_int which, struct rlimit *rlp); */ + struct rlimit rlp; + res = getrlimit(arg0, &rlp); + memBBWrt_alloc(arg1, (void*)&rlp, sizeof(rlp)); + break; + } + case SYS_compat_12_getdirentries: { + /* int getdirentries(int fd, char *buf, u_int count, + * long *basep); + */ + long64 basep64; + char *buf; + long basep; + buf = alloca(arg2); + res = getdirentries(arg0, buf, arg2, &basep); + memBBWrt_alloc(arg1, (void*)buf, arg2); + basep64 = basep; + memBBWrt_alloc(arg3, (void*)&basep64, sizeof(basep64)); + break; + } + case SYS_mmap: { + /* caddr_t mmap(caddr_t addr, size_t len, int prot, int flags, + * int fd, int pad, off_t pos); + */ + caddr_t addr; + ADDR arg, reloc; + addr = NULL; + reloc = arg0; + arg0 = nbsd_trunc_page(arg0); + reloc -= arg0; + arg1 += reloc; + arg6 -= reloc; + arg1 = nbsd_round_page(arg1); + /* Try to map where the process wants it. */ + arg = (arg0 != 0) ? verify_unmapped_pages(arg0, arg1) : 0; + if (arg == 0) { + if (arg3 & MAP_FIXED) + addr = unmap_mapped_pages(arg0, arg1); + else + arg0 = get_unmapped_pages(arg1); + } else + arg0 = arg; + if (arg0 == 0) { + errno = EINVAL; + res = -1; + break; + } + if (arg3 == MAP_STACK) + arg3 = MAP_ANON; + addr = mmap(addr, arg1, arg2, arg3, arg4, arg6); + if (addr != (void*)-1) { + for (arg = arg0; arg1 > 0; arg1 -= page_size) { + pmemMap(arg, addr); + arg += page_size; + addr += page_size; + } + *ret = arg0 + reloc; + goto out; + } + res = -1; + break; + } + case SYS_lseek: + /* off_t lseek(int fd, int pad, off_t offset, int whence); */ + res = lseek(arg0, arg2, arg3); + break; + case SYS___sysctl: { + /* int __sysctl(int *name, u_int namelen, void *old, + * size_t *oldlenp, void *new, size_t newlen); + */ + char *buf; + int *name; + size_t namelen, newlen, oldlen, *oldlenp; + void *new, *old; + namelen = arg1 << 2; + newlen = (arg4) ? arg5 : 0; + if (arg3 != 0L) { + memBBRd(arg3, (void*)&oldlen, sizeof(size_t)); + oldlenp = &oldlen; + } else { + oldlen = 0; + oldlenp = NULL; + } + buf = alloca(namelen + newlen + oldlen); + name = (void*)buf; + new = (newlen) ? buf + namelen : NULL; + old = (oldlen) ? buf + namelen + newlen : NULL; + memBBRd(arg0, (void*)name, namelen); + if (newlen) + memBBRd(arg4, new, newlen); + if (name[0] == CTL_HW && name[1] == HW_PAGESIZE && arg1 == 2) { + *oldlenp = sizeof(int); + *(int*)old = NBSD_PAGESIZE; + res = 0; + /* XXX: } else if (name[0] == CTL_KERN && name[1] == KERN_USRSTACK && */ + /* arg1 == 2) { */ + /* *oldlenp = sizeof(uint64_t); */ + /* *(uint64_t*)old = 0xA000000000000000ULL; */ + /* res = 0; */ + } else + res = sysctl(name, namelen >> 2, old, oldlenp, new, + newlen); + if (old != NULL) { + memBBWrt_alloc(arg3, (void*)oldlenp, sizeof(size_t)); + memBBWrt_alloc(arg2, old, oldlen); + } + break; + } + case SYS_poll: { + /* int poll(struct pollfd *fds, u_int nfds, int timeout); */ + struct pollfd *fds; + size_t fdssz; + fdssz = arg1 * sizeof(struct pollfd); + fds = alloca(fdssz); + memBBRd(arg0, (void*)fds, fdssz); + res = poll(fds, arg1, arg2); + memBBWrt(arg0, (void*)fds, fdssz); + break; + } + case SYS___clock_gettime50: { + /* int clock_gettime(clockid_t clock_id, struct timespec *tp); + */ + struct timespec ts; + struct timespec64 ts64; + res = clock_gettime(arg0, &ts); + ntos_timespec(&ts, &ts64); + memBBWrt_alloc(arg1, (void*)&ts64, sizeof(ts64)); + break; + } + case SYS_issetugid: + /* int issetugid(void); */ + *ret = issetugid(); + goto out; + case SYS___sigprocmask14: { + /* int sigprocmask(int how, const sigset_t *set, + * sigset_t *oset); + */ + sigset_t set, oset; + sigset_t *setp, *osetp; + if (arg1 != 0) { + setp = &set; + memBBRd(arg1, (void*)setp, sizeof(*setp)); + } else + setp = NULL; + osetp = (arg2 != 0) ? &oset : NULL; + res = sigprocmask(arg0, setp, osetp); + if (arg2 != 0) + memBBWrt_alloc(arg2, (void*)osetp, sizeof(*osetp)); + break; + } + case 416: { + /* int sigaction(int sig, const struct sigaction *act, + * struct sigaction *oact); + */ + struct sigaction64 sa; + if (arg2 != 0) { + res = signal_get_handler((int)arg0, &sa); + memBBWrt_alloc(arg2, (void*)&sa, sizeof(sa)); + } + if (arg1 != 0) { + memBBRd(arg1, (void*)&sa, sizeof(sa)); + res = signal_set_handler((int)arg0, &sa); + } + break; + } + default: + printf("syscall %d\n", num); + /* We'll give it a shot */ + res = __syscall(num, arg0, arg1, arg2, arg3, arg4, arg5); + break; + } + + if (res == -1) { + *ret = errno; + *status = ~0ULL; + } else + *ret = res; +#endif + + out: ; +#if 0 + printf(" = %llx,%llx\n", *status, *ret); +#endif + +} +