ref: 746e0c9217ab9ee1884b721a955b712d59b13549
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 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=%lux name=%s flags=%lux\n", fd, namet, flags);
if(copied)
free(namet);
if(fd < 0) {
noteerr(0, 1);
up->R[0] = fd;
return;
}
setcexec(up->fd, fd, flags & OCEXEC);
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(debug)
print("syscreate: name=%s\n", namet);
if(copied)
free(namet);
if(fd < 0) {
noteerr(0, 1);
up->R[0] = fd;
return;
}
setcexec(up->fd, fd, flags & OCEXEC);
up->R[0] = fd;
}
static void
_sysclose(void)
{
u32int fd;
fd = arg(0);
if(debug)
print("sysclose: fd=%lux\n", fd);
up->R[0] = noteerr(close(fd), 0);
if((fd & (1<<31)) == 0)
setcexec(up->fd, 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%lux off=0x%lux\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: fd=%ux buf=%s size=%lux off=%lux\n", fd, 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=%lux\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);
if(debug)
print("fd2path\n");
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;
name = arg(0);
namet = copyifnec(name, -1, &copied);
edir = arg(1);
nedir = arg(2);
edirt = bufifnec(edir, nedir, &buffered);
if(debug)
print("sysstat: edir=%s, nedir=%d\n", edirt, nedir);
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;
fd = arg(0);
edir = arg(1);
nedir = arg(2);
edirt = bufifnec(edir, nedir, &buffered);
if(debug)
print("sysfstat: edir=%s, nedir=%d\n", edirt, nedir);
up->R[0] = noteerr(fstat(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);
if(debug)
print("syswstate dir=%s, name=%s\n", edirt, namet);
up->R[0] = noteerr(wstat(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);
if(debug)
print("sysfwstat: %d, %#ux, %d\n",fd, edir, nedir);
up->R[0] = noteerr(fwstat(fd, edirt, nedir), nedir);
if(copied)
free(edirt);
}
static void
_sysexits(void)
{
if(arg(0) == 0) {
if(debug)
print("sysexits\n");
pexit("", 0);
} else {
if(debug)
print("sysexits: %s\n", vaddrnol(arg(0), 0));
pexit(vaddrnol(arg(0), 0), 0);
}
}
static void
_sysbrk(void)
{
ulong v;
Segment *s;
v = arg(0);
v = v + 7 & -8;
if(debug)
print("sysbrk v=%#lux\n", v);
if(v >= up->seg[ESEG]->start)
panic("bss > stack, wtf?");
if(v < up->seg[BSEG]->start)
panic("bss length < 0, wtf?");
s = up->seg[BSEG];
wlock(&s->rw);
s->dref = realloc(s->dref, v - s->start + sizeof(Ref));
if(s->dref == nil)
panic("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;
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);
if(debug)
print("syschdir\n");
up->R[0] = noteerr(chdir(dirt), 0);
if(copied)
free(dirt);
}
static void
_sysnotify(void)
{
u32int handler;
if(debug)
print("sysnotify\n");
handler = arg(0);
up->notehandler = handler;
up->R[0] = 0;
}
static void
_sysnoted(void)
{
u32int v;
v = arg(0);
if(debug)
print("sysnoted\n");
if(up->innote)
longjmp(up->notejmp, v + 1);
cherrstr("the front fell off");
up->R[0] = -1;
}
static void
_sysrfork(void)
{
u32int flags;
flags = arg(0);
if(debug)
print("rfork(%#o) for proc pid=%lud\n", flags, up->pid);
up->R[0] = noteerr(rfork(flags), 0);
}
static void
_sysexec(void)
{
u32int name, argv, *argvt;
char *namet, **argvv;
int i, argc, rc;
Segment *seg1, *seg2;
name = arg(0);
argv = arg(1);
namet = strdup(vaddr(name, 0, &seg1));
segunlock(seg1);
argvt = vaddr(argv, 0, &seg1);
if(debug)
fprint(2, "exec(%#ux=\"%s\", %#ux)\n", name, namet, argv);
for(argc = 0; argvt[argc]; argc++)
;
argvv = emalloc(sizeof(char *) * argc);
for(i = 0; i < argc; i++) {
argvv[i] = strdup(vaddr(argvt[i], 0, &seg2));
segunlock(seg2);
}
segunlock(seg1);
rc = loadtext(namet, argc, argvv);
for(i = 0; i < argc; i++)
free(argvv[i]);
free(argvv);
if(rc < 0)
up->R[0] = noteerr(rc, 0);
free(namet);
}
static void
_sysawait(void)
{
u32int s, n;
void *st;
int buffered;
s = arg(0);
n = arg(1);
st = bufifnec(s, n, &buffered);
if(debug)
print("sysawait\n");
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);
if(debug)
print("syspipe\n");
up->R[0] = noteerr(pipe((int *) fdt), 0);
if(buffered)
copyback(fd, 8, fdt);
}
static void
_sysdup(void)
{
u32int oldfd, newfd;
oldfd = arg(0);
newfd = arg(1);
if(debug)
print("sysdup\n");
up->R[0] = noteerr(dup2(oldfd, newfd), 0);
}
static void
_syssleep(void)
{
u32int n;
n = arg(0);
if(debug)
print("syssleep: nsec=%.8ux\n", n);
osmsleep(n);
up->R[0] = 0;
}
static void
_sysrendezvous(void)
{
uintptr_t tag, value;
tag = arg(0);
value = arg(1);
if(debug)
print("sysrendezvous: tag=%.8ux, value=%.8ux\n", tag, value);
up->R[0] = (u32int)(uintptr_t)(rendezvous((void*)(uintptr_t)tag, (void*)(uintptr_t)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);
if(debug)
print("sysmount: aname=%s\n", anamet);
} else {
anamet = nil;
copiedaname = 0;
if(debug)
print("sysmount\n");
}
up->R[0] = noteerr(mount(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);
if(debug)
print("sysbind: name=%s, old=%s\n", namet, oldt);
up->R[0] = noteerr(bind(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(debug)
print("sysunmount: name=%s, old=%s\n", name, oldt);
if(name == 0) {
namet = nil;
copiedname = 0;
up->R[0] = noteerr(unmount(nil, oldt), 0);
} else {
namet = copyifnec(name, -1, &copiedname);
up->R[0] = noteerr(unmount(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);
if(debug)
print("sysremove: file=%s\n", filet);
up->R[0] = noteerr(remove(filet), 0);
if(copied)
free(filet);
}
static void
_sysalarm(void)
{
u32int msec;
msec = arg(0);
if(debug)
print("sysalarm: msec=%.8ux\n", msec);
up->R[0] = alarm(msec);
}
static void
_syssemacquire(void)
{
u32int addr, block;
long *addrt;
addr = arg(0);
block = arg(1);
addrt = vaddrnol(addr, 4);
if(debug)
print("syssemacquire: addr=%s, block=%.8ux\n", addrt, block);
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);
if(debug)
print("syssemrelease: addr=%s, count=%.8ux\n", addrt, count);
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,
[AWAIT] = _sysawait,
[SEMACQUIRE]= _syssemacquire,
[SEMRELEASE]= _syssemrelease,
};
n = up->R[0];
calls[n]();
}