ref: 206fff9e92b75aa0e3151c2fd657e93bb458581c
dir: /kern/syscall.c/
#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]();
}