ref: 9c00c613885deba1ed19e905604571ef432cab11
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
setcexec(int fd, int flags)
{
Chan *c;
c = up->fgrp->fd[fd]; // get the Chan we just stored
if(c != nil){
if(flags & OCEXEC)
c->flag |= CCEXEC;
else
c->flag &= ~CCEXEC;
}
}
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
_sysr1(void)
{
if(!iseve())
error(Eperm);
up->R[0] = 0;
}
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);
#ifdef DSYSCALL
print("sysopen: pid=%d, fd=%lux name=%s flags=%lux\n", up->pid, fd, namet, flags);
#endif
if(copied)
free(namet);
if(fd < 0) {
noteerr(0, 1);
up->R[0] = -1;
return;
}
setcexec(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);
#ifdef DSYSCALL
print("syscreate: pid=%d, fd=%d name=%s\n", up->pid, fd, namet);
#endif
if(copied)
free(namet);
if(fd < 0) {
noteerr(0, 1);
up->R[0] = fd;
return;
}
setcexec(fd, flags & OCEXEC);
up->R[0] = fd;
}
static void
_sysclose(void)
{
u32int fd;
fd = arg(0);
#ifdef DSYSCALL
print("sysclose: pid=%d, fd=%lux\n",up->pid, fd);
#endif
up->R[0] = noteerr(close(fd), 0);
if((fd & (1<<31)) == 0)
setcexec(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);
#ifdef DSYSCALL
print("syspread: pid=%d, fd=%d size=0x%lux off=0x%lux\n", up->pid, fd, size, off);
#endif
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);
#ifdef DSYSCALL
print("syspwrite: pid=%d, fd=%ux buf=%s size=%lux off=%lux\n", up->pid, fd, buft, size, off);
#endif
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);
#ifdef DSYSCALL
print("sysseek: pid=%d, to=%d whence=%lux\n", up->pid, n, type);
#endif
*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);
#ifdef DSYSCALL
print("fd2path\n");
#endif
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);
#ifdef DSYSCALL
print("sysstat: pid=%d, name=%s, edir=%s, nedir=%d\n", up->pid, namet, edirt, nedir);
#endif
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);
#ifdef DSYSCALL
print("sysfstat: pid=%d edir=%s, nedir=%d\n", up->pid, edirt, nedir);
#endif
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);
#ifdef DSYSCALL
print("syswstate: pid=%d, dir=%s, name=%s\n", up->pid, edirt, namet);
#endif
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);
#ifdef DSYSCALL
print("sysfwstat: pid=%d, fd=%d, edir=%us, nedir=%d, copied=%d\n", up->pid, fd, edirt, nedir, copied);
#endif
up->R[0] = noteerr(fwstat(fd, edirt, nedir), nedir);
if(copied)
free(edirt);
}
static void
_sysexits(void)
{
if(arg(0) == 0) {
#ifdef DSYSCALL
print("sysexits: pid=%d\n", up->pid);
#endif
pexit("", 0);
} else {
#ifdef DSYSCALL
print("sysexits: pid=%d, status=%s\n", up->pid, vaddrnol(arg(0), 0));
#endif
pexit(vaddrnol(arg(0), 0), 0);
}
}
static void
_sysbrk(void)
{
ulong v;
Segment *s;
v = arg(0);
v = (v + 7) & -8;
#ifdef DSYSCALL
print("sysbrk: pid=%d v=%#lux\n", up->pid, v);
#endif
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
_sys_errstr(void)
{
/* Old binaries, implement if needed */
}
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);
#ifdef DSYSCALL
print("syserrstr: pid=%d, buf=%s\n", up->pid, buf);
#endif
up->R[0] = 0;
}
static void
_syschdir(void)
{
u32int dir;
char *dirt;
int copied;
dir = arg(0);
dirt = copyifnec(dir, -1, &copied);
#ifdef DSYSCALL
print("syschdir: pid=%d\n", up->pid);
#endif
up->R[0] = noteerr(chdir(dirt), 0);
if(copied)
free(dirt);
}
static void
_sysnotify(void)
{
u32int ft;
Segment *s;
int (*f)(void*, char*);
#ifdef DSYSCALL
print("sysnotify: pid=%d\n", up->pid);
#endif
ft = arg(0);
f = vaddr(ft, 0, &s);
up->notify = f;
up->R[0] = 0;
segunlock(s);
}
int
donotify(Ureg *ureg)
{
char *msg;
//if(up->procctl)
// procctl();
if(up->nnote == 0)
return 0;
qlock(&up->debug);
msg = popnote(ureg);
if(msg == nil){
qunlock(&up->debug);
return 0;
}
qunlock(&up->debug);
if(up->notify == nil){
if(up->lastnote->flag == NDebug)
pprint("suicide: %s\n", msg);
pexit(msg, up->lastnote->flag!=NDebug);
}
return 1;
}
static void
_sysnoted(void)
{
u32int v;
// TODO: Move to Ureg structure outright
v = arg(0);
#ifdef DSYSCALL
print("sysnoted: pid=%d\n", up->pid);
#endif
switch(v){
case NCONT: /* Resume at point where notified */
case NRSTR: /* Restore from NSAVE point*/
/* word under Ureg is old ureg */
//up->noteureg = *(Ureg**)((uintptr)nureg-8);
/* wet floor */
case NSAVE: /* Set save point to return to */
//if(noted(up->dbgreg, nureg, arg)){
// pprint("suicide: trap in noted\n");
// pexit("Suicide", 0);
//}
break;
default:
up->lastnote->flag = NDebug;
/* fall through */
case NDFLT: /* Perform default action */
//noted(up->dbgreg, nureg, v); /* for debugging */
if(up->lastnote->flag == NDebug)
pprint("suicide: %s\n", up->lastnote->msg);
pexit(up->lastnote->msg, up->lastnote->flag!=NDebug);
}
}
static void
_sysrfork(void)
{
u32int flags;
flags = arg(0);
#ifdef DSYSCALL
print("sysrfork(%#o) for proc pid=%lud\n", flags, up->pid);
#endif
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);
#ifdef DSYSCALL
print("sysexec(%#ux=\"%s\", %#ux) pid=%d\n", name, namet, argv, up->pid);
#endif
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);
/* Close files marked close-on-exec */
if(up->fgrp != nil) {
Chan *c;
lock(&up->fgrp->lk);
for(i = 2; i <= up->fgrp->maxfd; i++) {
c = up->fgrp->fd[i];
if(c != nil && (c->flag & CCEXEC)) {
up->fgrp->fd[i] = nil;
cclose(c);
}
}
unlock(&up->fgrp->lk);
}
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
_syssegbrk(void)
{
uintptr newbrk;
Segment *s;
uintptr base, oldbrk, oldsize, newsize;
Ref *newdref;
newbrk = arg(0); /* requested new break address */
/* Case: segbrk(0) → return current break (like sbrk(0)) */
if(newbrk == 0) {
s = up->seg[BSEG];
if(s == nil || s->start == 0) {
werrstr("no data segment");
up->R[0] = (int)-1;
return;
}
up->R[0] = s->start + s->size;
return;
}
/*
* Find the segment containing the address 'newbrk'.
* We reuse vaddr() with len=1 — it locks the segment if needed.
*/
s = nil;
vaddr(newbrk, 1, &s); /* will panic on segfault, which is fine */
/* Now s is valid and properly locked (rlock if SEGFLLOCK) */
/* Only allow growing BSS or attached memory segments */
if((s->type & SG_TYPE) != SG_BSS && s->type != SG_PHYSICAL) {
segunlock(s);
werrstr("segment not growable");
up->R[0] = (int)-1;
return;
}
base = s->start;
oldbrk = base + s->size;
oldsize = s->size;
/* Must be trying to grow (or stay the same) */
if(newbrk < oldbrk) {
segunlock(s);
werrstr("shrinking not supported");
up->R[0] = (int)-1;
return;
}
if(newbrk == oldbrk) {
/* No change — just return current break */
up->R[0] = oldbrk;
segunlock(s);
return;
}
/* Round up to 8-byte alignment (like your original _sysbrk) */
newsize = (newbrk - base + 7) & ~7;
/* Reallocate the data buffer */
newdref = realloc(s->dref, newsize + sizeof(Ref));
if(newdref == nil) {
segunlock(s);
werrstr("out of memory");
up->R[0] = (int)-1;
return;
}
/* Zero the new portion */
memset((char*)(newdref + 1) + oldsize, 0, newsize - oldsize);
/* Update segment */
s->dref = newdref;
s->data = newdref + 1;
s->size = newsize;
/* Success: return old break */
up->R[0] = oldbrk;
segunlock(s);
}
static void
_sysawait(void)
{
u32int s, n;
void *st;
int buffered;
s = arg(0);
n = arg(1);
st = bufifnec(s, n, &buffered);
#ifdef DSYSCALL
print("sysawait: pid=%d\n", up->pid);
#endif
up->R[0] = noteerr(sysawait(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);
#ifdef DSYSCALL
print("syspipe: pid=%d\n", up->pid);
#endif
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);
#ifdef DSYSCALL
print("sysdup: pid=%d\n", up->pid);
#endif
up->R[0] = noteerr(dup(oldfd, newfd), 0);
}
static void
_syssleep(void)
{
u32int n;
n = arg(0);
#ifdef DSYSCALL
print("syssleep: pid=%d nsec=%.8ux\n", up->pid, n);
#endif
if(n <= 0)
osyield();
else
osmsleep(n*1000);
up->R[0] = 0;
}
static void
_sysrendezvous(void)
{
uintptr_t tag, value;
tag = arg(0);
value = arg(1);
#ifdef DSYSCALL
print("sysrendezvous: pid=%d, tag=%.8ux, value=%.8ux\n", up->pid, tag, value);
#endif
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(!anamet)
anamet = "";
#ifdef DSYSCALL
print("sysmount: pid=%d, fd=%d, afd=%d, aname=%s\n", up->pid, fd, afd, anamet);
#endif
} else {
anamet = nil;
copiedaname = 0;
#ifdef DSYSCALL
print("sysmount: pid=%d, fd=%d, afd=%d\n", fd, afd, up->pid);
#endif
}
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);
#ifdef DSYSCALL
print("sysbind: pid=%d, name=%s, old=%s\n", up->pid, namet, oldt);
#endif
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);
#ifdef DSYSCALL
print("sysunmount: pid=%d, name=%s, old=%s\n", up->pid, name, oldt);
#endif
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
_sys_fsession(void)
{
/* deprecated; backwards compatibility only */
}
static void
_sysfauth(void)
{
u32int name;
Chan *c, *ac;
char *aname;
int fd, afd, copied;
fd = arg(0);
name = arg(1);
aname = copyifnec(name, -1, &copied);
if(!aname || aname[0] == '\0') {
up->R[0] = -1;
return;
}
c = fdtochan(fd, ORDWR, 0, 1);
if(waserror()){
cclose(c);
nexterror();
}
#ifdef DSYSCALL
print("sysfauth: pid=%d\n", up->pid);
#endif
ac = mntauth(c, aname);
/* at this point ac is responsible for keeping c alive */
poperror(); /* c */
cclose(c);
if(waserror()){
cclose(ac);
nexterror();
}
afd = newfd(ac);
print("afd: %d\n", afd);
up->R[0] = afd;
poperror(); /* ac */
}
static void
_sysremove(void)
{
u32int file;
char *filet;
int copied;
file = arg(0);
filet = copyifnec(file, -1, &copied);
#ifdef DSYSCALL
print("sysremove: pid=%d, file=%s\n", up->pid, filet);
#endif
up->R[0] = noteerr(remove(filet), 0);
if(copied)
free(filet);
}
static void
_sysalarm(void)
{
u32int msec;
msec = arg(0);
#ifdef DSYSCALL
print("sysalarm: pid=%d, msec=%.8ux\n", up->pid, msec);
#endif
up->R[0] = alarm(msec);
}
static void
_syssemacquire(void)
{
u32int addr, block;
long *addrt;
addr = arg(0);
block = arg(1);
addrt = vaddrnol(addr, 4);
#ifdef DSYSCALL
print("syssemacquire: pid=%d, addr=%s, block=%.8ux\n", up->pid, addrt, block);
#endif
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);
#ifdef DSYSCALL
print("syssemrelease: pid=%d, addr=%s, count=%.8ux\n", up->pid, addrt, count);
#endif
up->R[0] = noteerr(semrelease(addrt, count), 0);
segunlock(seg);
}
void
_syscall(void)
{
u32int n;
static void (*calls[])(void) = {
[SYSR1] = _sysr1,
[_ERRSTR] = _sys_errstr,
[BIND] = _sysbind,
[CHDIR] = _syschdir,
[CLOSE] = _sysclose,
[DUP] = _sysdup,
[ALARM] = _sysalarm,
[EXEC] = _sysexec,
[EXITS] = _sysexits,
[_FSESSION] = _sys_fsession,
[FAUTH] = _sysfauth,
//[_FSTAT] = _sys_fstat,
[SEGBRK] = _syssegbrk,
//[_MOUNT] = _sys_mount,
[OPEN] = _sysopen,
//[_READ] = _sys_read,
//[OSEEK] = _sysoseek,
[SLEEP] = _syssleep,
[_STAT] = _sysstat,
[RFORK] = _sysrfork,
//[_WRITE] = _sys_write,
[PIPE] = _syspipe,
[CREATE] = _syscreate,
[FD2PATH] = _sysfd2path,
[BRK_] = _sysbrk,
[REMOVE] = _sysremove,
//[_WSTAT] = _sys_wstat,
//[_FWSTAT] = _sys_fwstat,
[NOTIFY] = _sysnotify,
[NOTED] = _sysnoted,
//[SEGATTACH] = _syssegattach,
//[SEGDETACH] = _syssegdetach,
//[SEGFREE] = _syssegfree,
//[SEGFLUSH] = _syssegflush,
[RENDEZVOUS] = _sysrendezvous,
[UNMOUNT] = _sysunmount,
//[_WAIT] = _sys_wait,
[SEMACQUIRE] = _syssemacquire,
[SEMRELEASE] = _syssemrelease,
[SEEK] = _sysseek,
//[FVERSION] = _sysfversion,
[ERRSTR] = _syserrstr,
[STAT] = _sysstat,
[FSTAT] = _sysfstat,
[WSTAT] = _syswstat,
[FWSTAT] = _sysfwstat,
[MOUNT] = _sysmount,
[AWAIT] = _sysawait,
[PREAD] = _syspread,
[PWRITE] = _syspwrite,
//[TSEMACQUIRE] = _systsemacquire,
//[_NSEC] = _sys_nsec,
};
n = up->R[0];
calls[n]();
}