shithub: drawcpu

ref: 543763a08d4652736766543fa1369dec622ac886
dir: /kern/sysproc.c/

View raw version
#include "u.h"
#include <signal.h>
#include "lib.h"
#include "dat.h"
#include "fns.h"
#include "error.h"
#include "proc.h"
#include "user.h"
#include "sys.h"
#include <a.out.h>
#include <sys/mman.h>
#include <setjmp.h>

jmp_buf exec_jmp;
#define pgsize  0x1000

/* Use sizes from arm32 */
#define USTKTOP 0x3FFFFFFFULL
#define USTKSIZE 0x100000

void
devmask(Pgrp *pgrp, int invert, char *devs)
{
	int t, w;
	char *p;
	Rune r;
	u64int mask[nelem(pgrp->notallowed)];

	if(invert)
		memset(mask, 0xFF, sizeof mask);
	else		
		memset(mask, 0, sizeof mask);		

	w = sizeof mask[0] * 8;
	for(p = devs; *p != '\0';){
		p += chartorune(&r, p);
		t = devno(r);
		if(t == -1)
			continue;
		if(invert)
			mask[t/w] &= ~(1<<t%w);
		else
			mask[t/w] |= 1<<t%w;
	}

}

static void
copyname(char *file)
{
	char *p;
	
	p = strrchr(file, '/');
	if(p == nil)
		p = file;
	else
		p++;
	strncpy(up->name, p, NAMEMAX);

	if(up->path != nil && decref(up->path) == 0)
		free(up->path);
	up->path = malloc(sizeof(Ref) + strlen(file)+1);
    memset(up->path, 0, sizeof(Ref) + strlen(file)+1);
	incref(up->path);
	strcpy((char*)(up->path + 1), file);
}

static uvlong
_round(uvlong a, ulong b)
{
	uvlong w;

	w = (a/b)*b;
	if (a!=w)
		w += b;
	return(w);
}

int
procfdprint(Chan *c, int fd, char *s, int ns)
{
	return snprint(s, ns, "%3d %.2s %C %4ld (%.16llux %lud %.2ux) %5ld %8lld %s\n",
		fd,
		&"r w rw"[(c->mode&3)<<1],
		devtab[c->type]->dc, c->dev,
		c->qid.path, c->qid.vers, c->qid.type,
		8102, c->offset, c->path->s);
}

ulong
beswal(ulong l)
{
    uchar *p;
    p = (uchar*)&l;
    return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3];
}

uvlong
beswav(uvlong v)
{
    uchar *p;
    p = (uchar*)&v;
    return ((uvlong)p[0]<<56) | ((uvlong)p[1]<<48) | ((uvlong)p[2]<<40)
           | ((uvlong)p[3]<<32) | ((uvlong)p[4]<<24)
           | ((uvlong)p[5]<<16) | ((uvlong)p[6]<<8)
           | (uvlong)p[7];
}

void*
vmemchr(void *vs, int c, ulong n)
{
    jmp_buf env;
    volatile int ok;

    if (vs == NULL)
        return NULL;
    ok = setjmp(env);
    if (ok == 0) {
        const unsigned char *s = vs;
        const unsigned char *end = s + n;

        while (s < end) {
            if (*s == (unsigned char)c)
                return (void *)(uintptr_t)s;
            s++;
        }
    }
    /* fault → ok != 0 */
    return NULL;
}

static void
initstack(int argc, char **argv)
{
    ulong tos, sp, ap, size, i, len;
    
    tos = (USTKTOP & ~7) - sizeof(Tos) * 2;
	((Tos *) vaddrnol(tos, sizeof(Tos)))->pid = up->pid;

    sp = tos;
#ifdef DTRACE
    print("initstack: tos=%.8ux tossz=%.8ux USTKTOP=%.8ux\n", tos, sizeof(Tos), USTKTOP);
#endif
    size = 8;
    for(i = 0; i < argc; i++)
        size += strlen(argv[i]) + 5;

    sp -= size;
    sp &= ~7;
    up->R[0] = tos;
    up->R[1] = USTKTOP - 4;
    up->R[13] = sp;

	*(ulong *) vaddrnol(sp, 4) = argc;
    sp += 4;
    ap = sp + (argc + 1) * 4;
#ifdef DTRACE
    print("initstack: argc=%d sp=%.8ux ap=%.8ux\n", argc, sp, ap);
#endif
    for(i = 0; i < argc; i++) {
        *(ulong *) vaddrnol(sp, 4) = ap;
        sp += 4;
        len = strlen(argv[i]) + 1;
        memcpy(vaddrnol(ap, len), argv[i], len);
        ap += len;
    }
    *(ulong *) vaddrnol(sp, 4) = 0;
}

static int
loadscript(int fd, char *file, int argc, char **argv)
{
	char buf[513], *p, **q, **nargv;
	int rc, nargc, i;
	
	seek(fd, 0, 0);
	rc = readn(fd, buf, 512);
	if(rc <= 0)
		goto invalid;
	close(fd);
	buf[rc] = 0;
	p = strchr(buf, '\n');
	if(p == nil)
		goto invalid;
	*p = 0;
	while(isspace(*--p))
		*p = 0;
	nargc = 0;
	p = buf + 2;
	while(*p) {
		while(*p && isspace(*p))
			p++;
		nargc++;
		while(*p && !isspace(*p))
			p++;
	}
	if(nargc == 0)
		goto invalid;
	nargv = malloc(sizeof(char *) * (nargc + argc));
	q = nargv;
	p = buf + 2;
	while(*p) {
		while(*p && isspace(*p))
			p++;
		*(p-1) = 0;
		*q++ = p;
		while(*p && !isspace(*p))
			p++;
	}
	*q++ = file;
	for(i = 1; i < argc; i++)
		*q++ = argv[i];
	rc = loadtext(*nargv, argc + nargc, nargv);
	free(nargv);
	return rc;

invalid:
	werrstr("exec header invalid");
	return -1;
}

int
loadtext(char *file, int argc, char **argv)
{
    Segment *text, *data, *bss, *stack;
    uvlong txtaddr, txtsz, dataddr, datsz, datoff, bsssz, hdrsz;
    Exec hdr;
	char buf[2];
    int fd;

    fd = open(file, OREAD);
	if(fd < 0) return -1;
	up->arg = strdup(file);
	if(pread(fd, buf, 2, 0) == 2 && buf[0] == '#' && buf[1] == '!')
		return loadscript(fd, file, argc, argv);
	seek(fd, 0, 0);
    if(pread(fd, &hdr, sizeof(Exec), 0) != sizeof(Exec))
        panic("Short read on header\n");

    if(beswal(hdr.magic) != E_MAGIC)
        panic("bad magic number in exec header: got 0x%lux, want 0x%lux", beswal(hdr.magic), E_MAGIC);

    hdrsz = sizeof(Exec);
    txtaddr = pgsize + hdrsz;
    txtsz = beswal(hdr.text);
    dataddr = _round(pgsize+txtsz+hdrsz, pgsize);
    datsz = beswal(hdr.data);
    datoff = txtsz + hdrsz;
    bsssz = beswal(hdr.bss);

    copyname(file);

    freesegs();
    memset(up->R, 0, sizeof(up->R));
    up->CPSR = 0;
    text = newseg(txtaddr - hdrsz, txtsz + hdrsz, TSEG);
    data = newseg(dataddr, datsz, DSEG);
    bss = newseg(dataddr + datsz, bsssz, BSEG);
    stack = newseg((USTKTOP & ~7) - USTKSIZE, USTKSIZE, ESEG);
    seek(fd, 0, 0);
	if(readn(fd, text->data, txtsz + hdrsz) < txtsz + hdrsz)
		panic("%r");
	seek(fd, datoff, 0);
	if(readn(fd, data->data, datsz) < datsz)
		panic("%r");

	up->seg[TSEG] = text;
	up->seg[DSEG] = data;
	up->seg[BSEG] = bss;
	up->seg[ESEG] = stack;

    memset(bss->data, 0, bss->size);
    up->R[15] = beswal(hdr.entry);
    close(fd);
    initstack(argc, argv);

#ifdef DTRACE
    print("loadtext: PC=%.8ux, R1=%.8ux, R13=%.8ux\n", up->R[15], up->R[1], up->R[13]);
#endif
    resetvfp();
    return 0;
}


void
procrun(void *v)
{
	Ureg ureg;
	USED(v);
	for(;;) {
#ifdef DREGS
		dump();
#endif
		if(up->notepending)
            donotify(&ureg);
		step();
	}
}

int
sysrfork(int flag)
{
	Proc *p;
	Fgrp *ofg;
	Pgrp *opg;
	Rgrp *org;
	Egrp *oeg;
	char *devs = nil;
	int i, n;

	/* Check flags before we commit */
	if((flag & (RFFDG|RFCFDG)) == (RFFDG|RFCFDG))
		error(Ebadarg);
	if((flag & (RFNAMEG|RFCNAMEG)) == (RFNAMEG|RFCNAMEG))
		error(Ebadarg);
	if((flag & (RFENVG|RFCENVG)) == (RFENVG|RFCENVG))
		error(Ebadarg);
	if((flag&RFPROC) == 0) {
		if(flag & (RFMEM|RFNOWAIT))
			error(Ebadarg);
		if(flag & (RFFDG|RFCFDG)) {
			ofg = up->fgrp;
			if(flag & RFFDG)
				up->fgrp = dupfgrp(ofg);
			else
				up->fgrp = dupfgrp(nil);
			closefgrp(ofg);
		}
		if(flag & (RFNAMEG|RFCNAMEG)) {
			opg = up->pgrp;
			up->pgrp = newpgrp();
			if(flag & RFNAMEG)
				pgrpcpy(up->pgrp, opg);
			closepgrp(opg);
		}
		if(flag & RFNOMNT)
			devmask(up->pgrp, 1, devs);
		if(flag & RFREND) {
			org = up->rgrp;
			up->rgrp = newrgrp();
			closergrp(org);
		}
		if(flag & (RFENVG|RFCENVG)) {
			oeg = up->egrp;
			up->egrp = smalloc(sizeof(Egrp));
			up->egrp->ref.ref = 1;
			if(flag & RFENVG)
				envcpy(up->egrp, oeg);
			closeegrp(oeg);
		}
		if(flag & RFNOTEG){
			qlock(&up->debug);
			up->noteid = 0;
			qunlock(&up->debug);
		}
		return 0;
	}
	p = newproc();
	qlock(&up->debug);
	qlock(&p->debug);
	p->slash = cclone(up->slash);
	p->dot = cclone(up->dot);
	strecpy(p->text, p->text+sizeof p->text, up->text);
	p->kp = 0;

	p->nnote = 0;
 	p->notify = up->notify;
	p->notified = 0;
	p->notepending = 0;
	p->lastnote = nil;
	p->parentpid = up->pid;
	memset(p->ticks, 0, sizeof(p->ticks));
	p->ticks[TReal] = ticks();

	if((flag & RFNOTEG) == 0)
		p->noteid = up->noteid;

	/* Copy regs over */
	for(i = 1; i <= 15; i++)
		p->R[i] = up->R[i];
	p->R[0] = 0;
	
	p->CPSR = up->CPSR;
	p->FPSR = up->FPSR;
	if(up->procctl == Proc_tracesyscall)
		p->procctl = Proc_tracesyscall;

	qunlock(&p->debug);
	qunlock(&up->debug);

	/* Something broke! */
	if(waserror()){
		p->kp = 1;
		nexterror();
	}

	n = flag & RFMEM;
	qlock(&p->seglock);
	if(waserror()){
		qunlock(&p->seglock);
		nexterror();
	}
	for(i = 0; i < NSEG; i++)
		if(up->seg[i] != nil)
			p->seg[i] = dupseg(up->seg, i, n);
	qunlock(&p->seglock);
	poperror();

	/* File descriptors */
	if(flag & (RFFDG|RFCFDG)) {
		if(flag & RFFDG)
			p->fgrp = dupfgrp(up->fgrp);
		else
			p->fgrp = dupfgrp(nil);
	}
	else {
		p->fgrp = up->fgrp;
		incref(&up->fgrp->ref);
	}

	/* Process groups */
	if(flag & (RFNAMEG|RFCNAMEG)) {
		p->pgrp = newpgrp();
		pgrpcpy(p->pgrp, up->pgrp);
	} else {
		p->pgrp = up->pgrp;
		incref(&p->pgrp->ref);
	}
	if(flag & RFREND)
		p->rgrp = newrgrp();
	else {
		p->rgrp = up->rgrp;
		incref(&up->rgrp->ref);
	}

	/* Environment group */
	if(flag & (RFENVG|RFCENVG)) {
		p->egrp = smalloc(sizeof(Egrp));
		p->egrp->ref.ref = 1;
		if(flag & RFENVG)
			envcpy(p->egrp, up->egrp);
	} else {
		p->egrp = up->egrp;
		incref(&p->egrp->ref);
	}
	p->fn = procrun;
	p->parent = up;
	up->child = p;
	p->arg = 0;

	poperror();
	
	if(flag & RFNOMNT)
		devmask(p->pgrp, 1, devs);

	if((flag&RFNOWAIT) == 0){
		lock(&up->exl);
		up->nchild++;
		unlock(&up->exl);
	}

	osproc(p);
	return p->pid;
}