shithub: drawcpu

ref: 206fff9e92b75aa0e3151c2fd657e93bb458581c
dir: /kern/syscall.c/

View raw version
#include "u.h"
#include "lib.h"
#include "dat.h"
#include "fns.h"
#include "error.h"
#include "user.h"
#include "sys.h"
#include "proc.h"

static void *
emalloc(int n)
{
	void *p;
	if(n==0)
		n=1;
	p = malloc(n);
	if(p == nil)
		sysfatal("out of memory");
	memset(p, 0, n);
	setmalloctag(p, getcallerpc(&n));
	return p;
}

static char*
estrdup(char *s)
{
	char *d;
	int n;

	n = strlen(s)+1;
	d = emalloc(n);
	memmove(d, s, n);
	return d;
}

static u32int
arg(int n)
{
	/* no locking necessary, since we're on the stack */
	return *(u32int*) vaddrnol(up->R[13] + 4 + 4 * n, 4);
}

static u64int
argv(int n)
{
	return arg(n) | ((u64int)arg(n+1) << 32);
}

u32int
noteerr(u32int x, u32int y)
{
	if(((int)x) >= ((int)y))
		return x;
	rerrstr(up->errstr, ERRMAX);
	return x;
}

void
cherrstr(char *str, ...)
{
	va_list va;
	
	va_start(va, str);
	vsnprint(up->errstr, ERRMAX, str, va);
	va_end(va);
}

static void
_sysopen(void)
{
	u32int name, flags;
	char *namet;
	int fd, copied;
	name = arg(0);
	flags = arg(1);
	namet = copyifnec(name, -1, &copied);
	fd = open(namet, flags);
	if(debug)
		print("sysopen: fd=%.8ux name=%s flags=%.8ux\n", fd, namet, flags);
	if(copied)
		free(namet);
	if(fd < 0) {
		noteerr(0, 1);
		up->R[0] = fd;
		return;
	}
	up->R[0] = fd;
}

static void
_syscreate(void)
{
	u32int name, flags, perm;
	char *namet;
	int fd, copied;
	
	name = arg(0);
	flags = arg(1);
	perm = arg(2);
	namet = copyifnec(name, -1, &copied);
	fd = create(namet, flags, perm);
	if(copied)
		free(namet);
	if(fd < 0) {
		noteerr(0, 1);
		up->R[0] = fd;
		return;
	}
	up->R[0] = fd;
}

static void
_sysclose(void)
{
	u32int fd;
	
	fd = arg(0);
	if(debug)
		print("sysclose: fd=%.8ux\n", fd);
	up->R[0] = noteerr(close(fd), 0);
}

static void
_syspread(void)
{
	int buffered;
	u32int fd, size, buf;
	u64int off;
	void *targ;
	
	fd = arg(0);
	buf = arg(1);
	size = arg(2);
	off = argv(3);
	if(debug)
		print("syspread: size=0x%.8ux off=0x%.8ux\n", size, off);
	targ = bufifnec(buf, size, &buffered);
	up->R[0] = noteerr(pread(fd, targ, size, off), size);
	if(buffered)
		copyback(buf, up->R[0], targ);
}

static void
_syspwrite(void)
{
	u32int fd, size, buf;
	u64int off;
	int copied;
	void *buft;
	
	fd = arg(0);
	buf = arg(1);
	size = arg(2);
	off = argv(3);
	buft = copyifnec(buf, size, &copied);
	if(debug)
		print("syspwrite: buf=%s size=%.8ux off=%.8ux\n", buft, size, off);
	up->R[0] = noteerr(pwrite(fd, buft, size, off), size);
	if(copied)
		free(buft);
}

static void
_sysseek(void)
{
	u32int fd, type;
	vlong n, *ret;
	Segment *seg;
	
	ret = vaddr(arg(0), 8, &seg);
	fd = arg(1);
	n = argv(2);
	type = arg(4);
	if(debug)
		print("sysseek: to=%d whence=%.4ux\n", n, type);
	*ret = seek(fd, n, type);
	if(*ret < 0) noteerr(0, 1);
	segunlock(seg);
}

static void
_sysfd2path(void)
{
	u32int fd, buf, nbuf;
	void *buft;
	int buffered;
	
	fd = arg(0);
	buf = arg(1);
	nbuf = arg(2);
	buft = bufifnec(buf, nbuf, &buffered);
	up->R[0] = noteerr(fd2path(fd, buft, nbuf), 0);
	if(buffered)
		copyback(buf, nbuf, buft);
}

static void
_sysstat(void)
{
    u32int name, edir, nedir;
    char *namet;
    void *edirt;
    int copied, buffered;
    Segment *seg;
	print("sysstat\n");

    name = arg(0); // R0
	if(debug)
	    print("sysstat: name=%.8ux, R13=%.8ux\n", name, up->R[13]);
    if (!vaddr(name, 1, &seg)) {
        print("sysstat: invalid name pointer %.8ux\n", name);
        cherrstr("invalid name pointer");
        up->R[0] = -1;
        return;
    }
    namet = copyifnec(name, -1, &copied);
    edir = arg(1); // R1
    nedir = arg(2); // R2
	if(debug)
	    print("sysstat: edir=%.8ux, nedir=%d\n", edir, nedir);
    if (nedir > 0 && !vaddr(edir, nedir, &seg)) {
        print("sysstat: invalid edir pointer %.8ux\n", edir);
        cherrstr("invalid edir pointer");
        if (copied)
            free(namet);
        up->R[0] = -1;
        return;
    }
    edirt = bufifnec(edir, nedir, &buffered);
    up->R[0] = noteerr(stat(namet, edirt, nedir), nedir);
    if (copied)
        free(namet);
    if (buffered)
        copyback(edir, up->R[0], edirt);
}

static void
_sysfstat(void)
{
	u32int fd, edir, nedir;
	void *edirt;
	int buffered;
	if(debug)
		print("sysfstat\n");
	fd = arg(0);
	edir = arg(1);
	nedir = arg(2);
	edirt = bufifnec(edir, nedir, &buffered);
	up->R[0] = noteerr(sysfstat(fd, edirt, nedir), nedir);
	if(buffered)
		copyback(edir, up->R[0], edirt);
}

static void
_syswstat(void)
{
	u32int name, edir, nedir;
	char *namet;
	void *edirt;
	int copied, copied2;
	
	name = arg(0);
	namet = copyifnec(name, -1, &copied);
	edir = arg(1);
	nedir = arg(2);
	edirt = copyifnec(edir, nedir, &copied2);
	up->R[0] = noteerr(syswstat(namet, edirt, nedir), nedir);
	if(copied)
		free(namet);
	if(copied2)
		free(edirt);
}

static void
_sysfwstat(void)
{
	u32int fd, edir, nedir;
	void *edirt;
	int copied;
	
	fd = arg(0);
	edir = arg(1);
	nedir = arg(2);
	edirt = copyifnec(edir, nedir, &copied);
	up->R[0] = noteerr(sysfwstat(fd, edirt, nedir), nedir);
	if(copied)
		free(edirt);
}

static void
_sysexits(void)
{
	if(arg(0) == 0)
		exits(nil);
	else
		exits(vaddrnol(arg(0), 0));
}

static void
_sysbrk(void)
{
	ulong v;
	Segment *s;
	if(debug)
		print("sysbrk\n");
	v = arg(0);
	v = v + 7 & -8;
	if(v >= up->S[SEGSTACK]->start)
		fprint(2, "bss > stack, wtf?");
	if(v < up->S[SEGBSS]->start)
		fprint(2, "bss length < 0, wtf?");
	s = up->S[SEGBSS];
	wlock(&s->rw);
	s->dref = realloc(s->dref, v - s->start + sizeof(Ref));
	if(s->dref == nil)
		fprint(2, "error reallocating");
	s->data = s->dref + 1;
	if(s->size < v - s->start)
		memset((char*)s->data + s->size, 0, v - s->start - s->size);
	s->size = v - s->start;
	up->R[0] = 0;
	wunlock(&s->rw);
}

static void
_syserrstr(void)
{
	char buf[ERRMAX], *srct;
	u32int src, len;
	int copied;
	print("We're in syserrstr\n");
	src = arg(0);
	len = arg(1);
	srct = copyifnec(src, len, &copied);
	strcpy(buf, up->errstr);
	utfecpy(up->errstr, up->errstr + ERRMAX, srct);
	utfecpy(srct, srct + len, buf);
	if(copied)
		copyback(src, len, srct);
	up->R[0] = 0;
}

static void
_syschdir(void)
{
	u32int dir;
	char *dirt;
	int copied;
	
	dir = arg(0);
	dirt = copyifnec(dir, -1, &copied);
	up->R[0] = noteerr(syschdir(dirt), 0);
	if(copied)
		free(dirt);
}

static void
_sysnotify(void)
{
	u32int handler;
	
	handler = arg(0);
	up->notehandler = handler;
	up->R[0] = 0;
}

static void
_sysnoted(void)
{
	u32int v;
	
	v = arg(0);
	if(up->innote)
		longjmp(up->notejmp, v + 1);
	cherrstr("the front fell off");
	up->R[0] = -1;
}

static void
_sysrfork(void)
{
	u32int flags;
	int rc, i;
	Segment *s, *t;
	Proc *p;
	
	flags = arg(0);
	if((flags & (RFFDG | RFCFDG)) == (RFFDG | RFCFDG) ||
	   (flags & (RFNAMEG | RFCNAMEG)) == (RFNAMEG | RFCNAMEG) ||
	   (flags & (RFENVG | RFCENVG)) == (RFENVG | RFCENVG)) {
		werrstr("bad arg in rfork");
		up->R[0] = -1;
		return;
	}
	if((flags & RFPROC) == 0) {
		if(flags & RFFDG) {
			Fgrp *old = up->fgrp;
			up->fgrp = dupfgrp(up->fgrp);
			closefgrp(old);
		}
		if(flags & RFCFDG) {
			Fgrp *old = up->fgrp;
			up->fgrp = dupfgrp(nil);
			closefgrp(old);
		}
		up->R[0] = noteerr(sysrfork(flags), 0);
		return;
	}
	p = newproc();
	if(p == nil) {
		fprint(2, "rfork: malloc failed for Proc");
		werrstr("rfork: malloc failed");
		up->R[0] = -1;
		return;
	}
	memset(p, 0, sizeof(Proc));
	memcpy(p, up, sizeof(Proc));
	for(i = 0; i < SEGNUM; i++) {
		s = p->S[i];
		if(s == nil)
			continue;
		if((flags & RFMEM) == 0 && i != SEGTEXT || i == SEGSTACK) {
			t = newseg(s->start, s->size, s->flags);
			if(t == nil) {
				fprint(2, "rfork: newseg failed");
				werrstr("rfork: newseg failed");
				up->R[0] = -1;
				return;
			}
			t->dref = mallocz(sizeof(Ref) + s->size, 1);
			if(t->dref == nil) {
				fprint(2, "rfork: malloc failed for Segment data");
				werrstr("rfork: malloc failed");
				up->R[0] = -1;
				return;
			}
			incref(t->dref);
			t->data = t->dref + 1;
			memcpy(t->data, s->data, s->size);
			p->S[i] = t;
		} else {
			incref(s->dref);
			incref(&s->ref);
		}
	}
	if(flags & RFFDG)
		p->fgrp = dupfgrp(up->fgrp);
	else if(flags & RFCFDG)
		p->fgrp = dupfgrp(nil);
	else
		incref(&up->fgrp->ref);
	if(flags & RFNAMEG)
		p->pgrp = newpgrp();
	else
		incref(&up->pgrp->ref);
	if(flags & RFENVG)
		p->egrp = newegrp();
	else
		incref(&up->egrp->ref);
	rc = sysrfork(flags);
	if(rc < 0) {
		fprint(2, "rfork: sysrfork failed: %r");
		werrstr("rfork: %r");
		up->R[0] = -1;
		return;
	}
	if(rc == 0) {
		_setproc(p);
		atexit((void(*)(void))pexit);
		p->pid = getpid();
		inittos();
		osproc(p);
	}
	up->R[0] = rc;
}

static void
_sysexec(void)
{
	u32int name, argv;
	char *namet;
	char **argvv;
	int i, argc, rc;
	Segment *seg1, *seg2;
	u32int *argvt;
	
	name = arg(0);
	argv = arg(1);
	namet = estrdup((char*)vaddrnol(name, 0));
	argvt = vaddr(argv, 0, &seg1);
	for(argc = 0; argvt[argc]; argc++)
		;
	argvv = mallocz(sizeof(char *) * (argc + 1), 1);
	if(argvv == nil) {
		fprint(2, "exec: malloc failed for argv");
		werrstr("exec: malloc failed");
		up->R[0] = -1;
		free(namet);
		return;
	}
	for(i = 0; i < argc; i++) {
		argvv[i] = estrdup((char*)vaddrnol(argvt[i], 0));
	}
	argvv[argc] = nil;
	segunlock(seg1);
	rc = loadtext(namet, argc, argvv);
	for(i = 0; i < argc; i++)
		free(argvv[i]);
	free(argvv);
	free(namet);
	if(rc < 0)
		up->R[0] = noteerr(rc, 0);
}

static void
_sysawait(void)
{
	u32int s, n;
	void *st;
	int buffered;
	
	s = arg(0);
	n = arg(1);
	st = bufifnec(s, n, &buffered);
	up->R[0] = noteerr(await(st, n), 0);
	if(buffered)
		copyback(s, up->R[0], st);
}

static void
_syspipe(void)
{
	u32int fd, *fdt;
	int buffered;
	
	fd = arg(0);
	fdt = bufifnec(fd, 8, &buffered);
	up->R[0] = noteerr(syspipe((int *) fdt), 0);
	if(buffered)
		copyback(fd, 8, fdt);
}

static void
_sysdup(void)
{
	u32int oldfd, newfd;
	
	oldfd = arg(0);
	newfd = arg(1);
	up->R[0] = noteerr(dup2(oldfd, newfd), 0);
}

static void
_syssleep(void)
{
	u32int n;
	
	n = arg(0);
	osmsleep(n);
	up->R[0] = 0;
}

static void
_sysrendezvous(void)
{
	u32int tag, value;
	
	tag = arg(0);
	value = arg(1);
	up->R[0] = (u32int) (uintptr)sysrendezvous((void *)tag, (void *)value);
	if(up->R[0] == ~0)
		noteerr(0, 1);
}

static void
_sysmount(void)
{
	u32int fd, afd, old, flag, aname;
	char *oldt, *anamet;
	int copiedold, copiedaname;
	
	fd = arg(0);
	afd = arg(1);
	old = arg(2);
	flag = arg(3);
	aname = arg(4);
	oldt = copyifnec(old, -1, &copiedold);
	if(aname) {
		anamet = copyifnec(aname, -1, &copiedaname);
	} else {
		anamet = nil;
		copiedaname = 0;
	}
	up->R[0] = noteerr(sysmount(fd, afd, oldt, flag, anamet), 0);
	if(copiedold)
		free(oldt);
	if(copiedaname)
		free(anamet);
}

static void
_sysbind(void)
{
	u32int name, old, flags;
	char *namet, *oldt;
	int copiedname, copiedold;
	
	name = arg(0);
	old = arg(1);
	flags = arg(2);
	namet = copyifnec(name, -1, &copiedname);
	oldt = copyifnec(old, -1, &copiedold);
	up->R[0] = noteerr(sysbind(namet, oldt, flags), 0);
	if(copiedname)
		free(namet);
	if(copiedold)
		free(oldt);
}

static void
_sysunmount(void)
{
	u32int name, old;
	char *namet, *oldt;
	int copiedname, copiedold;
	
	name = arg(0);
	old = arg(1);
	oldt = copyifnec(old, -1, &copiedold);
	if(name == 0) {
		namet = nil;
		copiedname = 0;
		up->R[0] = noteerr(sysunmount(nil, oldt), 0);
	} else {
		namet = copyifnec(name, -1, &copiedname);
		up->R[0] = noteerr(sysunmount(namet, oldt), 0);
	}
	if(copiedold)
		free(oldt);
	if(copiedname)
		free(namet);
}

static void
_sysremove(void)
{
	u32int file;
	char *filet;
	int copied;
	
	file = arg(0);
	filet = copyifnec(file, -1, &copied);
	up->R[0] = noteerr(sysremove(filet), 0);
	if(copied)
		free(filet);
}

static void
_sysalarm(void)
{
	u32int msec;
	
	msec = arg(0);
	up->R[0] = alarm(msec);
}

static void
_syssemacquire(void)
{
	u32int addr, block;
	long *addrt;

	addr = arg(0);
	block = arg(1);
	addrt = vaddrnol(addr, 4);
	up->R[0] = noteerr(semacquire(addrt, block), 0);
}

static void
_syssemrelease(void)
{
	u32int addr, count;
	long *addrt;
	Segment *seg;

	addr = arg(0);
	count = arg(1);
	addrt = vaddr(addr, 4, &seg);
	up->R[0] = noteerr(semrelease(addrt, count), 0);
	segunlock(seg);
}

void
_syscall(void)
{
    u32int n;
    static void (*calls[])(void) = {
        [EXITS]     = _sysexits,
        [CLOSE]     = _sysclose,
        [OPEN]      = _sysopen,
        [CREATE]    = _syscreate,
        [PREAD]     = _syspread,
        [PWRITE]    = _syspwrite,
        [BRK_]      = _sysbrk,
        [ERRSTR]    = _syserrstr,
        [STAT]      = _sysstat,
        [FSTAT]     = _sysfstat,
        [WSTAT]     = _syswstat,
        [FWSTAT]    = _sysfwstat,
        [SEEK]      = _sysseek,
        [CHDIR]     = _syschdir,
        [FD2PATH]   = _sysfd2path,
        [NOTIFY]    = _sysnotify,
        [NOTED]     = _sysnoted,
        [RFORK]     = _sysrfork,
        [EXEC]      = _sysexec,
        [PIPE]      = _syspipe,
        [SLEEP]     = _syssleep,
        [RENDEZVOUS]= _sysrendezvous,
        [BIND]      = _sysbind,
        [UNMOUNT]   = _sysunmount,
        [DUP]       = _sysdup,
        [MOUNT]     = _sysmount,
        [REMOVE]    = _sysremove,
        [ALARM]     = _sysalarm,
        [SEMACQUIRE]= _syssemacquire,
        [SEMRELEASE]= _syssemrelease,
    };

    n = up->R[0];

    calls[n]();
}