$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 <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/sysctl.h>
+#include <sys/syslimits.h>
+#include <sys/time.h>
+#include <sys/mount.h>
+#include <sys/resource.h>
+#include <assert.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <signal.h>
+#include <string.h>
+#include <unistd.h>
+
+#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
+
+}
+
