Exemple #1
0
void
pexit(char *exitstr, int freemem)
{
	Proc *up = externup();
	Proc *p;
	Segment **s, **es;
	int32_t utime, stime;
	Waitq *wq, *f, *next;
	Fgrp *fgrp;
	Egrp *egrp;
	Rgrp *rgrp;
	Pgrp *pgrp;
	Chan *dot;

	if(0 && up->nfullq > 0)
		iprint(" %s=%d", up->text, up->nfullq);
	if(0 && up->nicc > 0)
		iprint(" [%s nicc %ud tctime %ulld actime %ulld]\n",
			up->text, up->nicc, up->tctime, up->actime);
	if(up->syscalltrace != nil)
		free(up->syscalltrace);
	up->syscalltrace = nil;
	up->alarm = 0;
	clearwakeups(up);

	if (up->Timer.tt)
		timerdel(&up->Timer);
	if(up->trace)
		proctrace(up, SDead, 0);

	/* nil out all the resources under lock (free later) */
	qlock(&up->debug);
	fgrp = up->fgrp;
	up->fgrp = nil;
	egrp = up->egrp;
	up->egrp = nil;
	rgrp = up->rgrp;
	up->rgrp = nil;
	pgrp = up->pgrp;
	up->pgrp = nil;
	dot = up->dot;
	up->dot = nil;
	qunlock(&up->debug);


	if(fgrp)
		closefgrp(fgrp);
	if(egrp)
		closeegrp(egrp);
	if(rgrp)
		closergrp(rgrp);
	if(dot)
		cclose(dot);
	if(pgrp)
		closepgrp(pgrp);

	/*
	 * if not a kernel process and have a parent,
	 * do some housekeeping.
	 */
	if(up->kp == 0) {
		p = up->parent;
		if(p == 0) {
			if(exitstr == 0)
				exitstr = "unknown";
			//die("bootprocessdeath");
			panic("boot process died: %s", exitstr);
		}

		while(waserror())
			;

		wq = smalloc(sizeof(Waitq));
		poperror();

		wq->w.pid = up->pid;
		utime = up->time[TUser] + up->time[TCUser];
		stime = up->time[TSys] + up->time[TCSys];
		wq->w.time[TUser] = tk2ms(utime);
		wq->w.time[TSys] = tk2ms(stime);
		wq->w.time[TReal] = tk2ms(sys->machptr[0]->ticks - up->time[TReal]);
		if(exitstr && exitstr[0])
			snprint(wq->w.msg, sizeof(wq->w.msg), "%s %d: %s",
				up->text, up->pid, exitstr);
		else
			wq->w.msg[0] = '\0';

		lock(&p->exl);
		/*
		 * Check that parent is still alive.
		 */
		if(p->pid == up->parentpid && p->state != Broken) {
			p->nchild--;
			p->time[TCUser] += utime;
			p->time[TCSys] += stime;
			/*
			 * If there would be more than 128 wait records
			 * processes for my parent, then don't leave a wait
			 * record behind.  This helps prevent badly written
			 * daemon processes from accumulating lots of wait
			 * records.
		 	 */
			if(p->nwait < 128) {
				wq->next = p->waitq;
				p->waitq = wq;
				p->nwait++;
				wq = nil;
				wakeup(&p->waitr);
			}
		}
		unlock(&p->exl);
		if(wq)
			free(wq);
	}

	if(!freemem)
		addbroken(up);

	qlock(&up->seglock);
	es = &up->seg[NSEG];
	for(s = up->seg; s < es; s++) {
		if(*s) {
			putseg(*s);
			*s = 0;
		}
	}
	qunlock(&up->seglock);

	lock(&up->exl);		/* Prevent my children from leaving waits */
	psunhash(up);
	up->pid = 0;
	wakeup(&up->waitr);
	unlock(&up->exl);

	for(f = up->waitq; f; f = next) {
		next = f->next;
		free(f);
	}

	/* release debuggers */
	qlock(&up->debug);
	if(up->pdbg) {
		wakeup(&up->pdbg->sleep);
		up->pdbg = 0;
	}
	qunlock(&up->debug);

	/* Sched must not loop for these locks */
	lock(&procalloc.l);
	lock(&pga.l);

	stopac();
	edfstop(up);
	up->state = Moribund;
	sched();
	panic("pexit");
}
Exemple #2
0
static void
releaseintr(Ureg* ureg, Timer *t)
{
	Proc *up = externup();
	Proc *p;
	extern int panicking;
	Sched *sch;
	Schedq *rq;

	if(panicking || active.exiting)
		return;

	p = t->ta;
	if((edflock(p)) == nil)
		return;
	sch = procsched(p);
	DPRINT("%lu releaseintr %d[%s]\n", now, p->pid, statename[p->state]);
	switch(p->state){
	default:
		edfunlock();
		return;
	case Ready:
		/* remove proc from current runq */
		rq = &sch->runq[p->priority];
		if(dequeueproc(sch, rq, p) != p){
			DPRINT("releaseintr: can't find proc or lock race\n");
			release(p);	/* It'll start best effort */
			edfunlock();
			return;
		}
		p->state = Waitrelease;
		/* fall through */
	case Waitrelease:
		release(p);
		edfunlock();
		if(p->state == Wakeme){
			iprint("releaseintr: wakeme\n");
		}
		ready(p);
		if(up){
			up->delaysched++;
			sch->delayedscheds++;
		}
		return;
	case Running:
		release(p);
		edfrun(p, 1);
		break;
	case Wakeme:
		release(p);
		edfunlock();
		if(p->trend)
			wakeup(p->trend);
		p->trend = nil;
		if(up){
			up->delaysched++;
			sch->delayedscheds++;
		}
		return;
	}
	edfunlock();
}
Exemple #3
0
/*
 * Move the current process to an application core.
 * This is performed at the end of execac(), and
 * we pretend to be returning to user-space, but instead we
 * dispatch the process to another core.
 * 1. We do the final bookkeeping that syscall() would do after
 *    a return from sysexec(), because we are not returning.
 * 2. We dispatch the process to an AC using an ICC.
 *
 * This function won't return unless the process is reclaimed back
 * to the time-sharing core, and is the handler for the process
 * to deal with traps and system calls until the process dies.
 *
 * Remember that this function is the "line" between user and kernel
 * space, it's not expected to raise|handle any error.
 *
 * We install a safety error label, just in case we raise errors,
 * which we shouldn't. (noerrorsleft knows that for exotic processes
 * there is an error label pushed by us).
 */
void
runacore(void)
{
	Proc *up = externup();
	Ureg *ureg;
	void (*fn)(void);
	int rc, flush, s;
	char *n;
	uint64_t t1;

	if(waserror())
		panic("runacore: error: %s\n", up->errstr);
	ureg = up->dbgreg;
	fakeretfromsyscall(ureg);
	fpusysrfork(ureg);

	procpriority(up, PriKproc, 1);
	rc = runac(up->ac, actouser, 1, nil, 0);
	procpriority(up, PriNormal, 0);
	for(;;){
		t1 = fastticks(nil);
		flush = 0;
		fn = nil;
		switch(rc){
		case ICCTRAP:
			s = splhi();
			machp()->MMU.cr2 = up->ac->MMU.cr2;
			DBG("runacore: trap %llu cr2 %#llx ureg %#p\n",
				ureg->type, machp()->MMU.cr2, ureg);
			switch(ureg->type){
			case IdtIPI:
				if(up->procctl || up->nnote)
					notify(up->dbgreg);
				if(up->ac == nil)
					goto ToTC;
				kexit(up->dbgreg);
				break;
			case IdtNM:
			case IdtMF:
			case IdtXF:
				/* these are handled in the AC;
				 * If we get here, they left in m->NIX.icc->data
				 * a note to be posted to the process.
				 * Post it, and make the vector a NOP.
				 */
				n = up->ac->NIX.icc->note;
				if(n != nil)
					postnote(up, 1, n, NDebug);
				ureg->type = IdtIPI;		/* NOP */
				break;
			default:
				cr3put(machp()->MMU.pml4->pa);
				if(0 && ureg->type == IdtPF){
					print("before PF:\n");
					print("AC:\n");
					dumpptepg(4, up->ac->MMU.pml4->pa);
					print("\n%s:\n", rolename[NIXTC]);
					dumpptepg(4, machp()->MMU.pml4->pa);
				}
				trap(ureg);
			}
			splx(s);
			flush = 1;
			fn = actrapret;
			break;
		case ICCSYSCALL:
			DBG("runacore: syscall ax %#llx ureg %#p\n",
				ureg->ax, ureg);
			cr3put(machp()->MMU.pml4->pa);
			//syscall(ureg->ax, ureg);
			flush = 1;
			fn = acsysret;
			if(0)
			if(up->nqtrap > 2 || up->nsyscall > 1)
				goto ToTC;
			if(up->ac == nil)
				goto ToTC;
			break;
		default:
			panic("runacore: unexpected rc = %d", rc);
		}
		up->tctime += fastticks2us(fastticks(nil) - t1);
		procpriority(up, PriExtra, 1);
		rc = runac(up->ac, fn, flush, nil, 0);
		procpriority(up, PriNormal, 0);
	}
ToTC:
	/*
	 *  to procctl, then syscall,  to
	 *  be back in the TC
	 */
	DBG("runacore: up %#p: return\n", up);
}
Exemple #4
0
/*
 *  Call user, if necessary, with note.
 *  Pass user the Ureg struct and the note on his stack.
 */
int
notify(Ureg* ureg)
{
	Proc *up = externup();
	int l;
	Mpl pl;
	Note note;
	uintptr_t sp;
	NFrame *nf;

	/*
	 * Calls procctl splhi, see comment in procctl for the reasoning.
	 */
	if(up->procctl)
		procctl(up);
	if(up->nnote == 0)
		return 0;

	fpunotify(ureg);

	pl = spllo();
	qlock(&up->debug);

	up->notepending = 0;
	memmove(&note, &up->note[0], sizeof(Note));
	if(strncmp(note.msg, "sys:", 4) == 0){
		l = strlen(note.msg);
		if(l > ERRMAX-sizeof(" pc=0x0123456789abcdef"))
			l = ERRMAX-sizeof(" pc=0x0123456789abcdef");
		sprint(note.msg+l, " pc=%#p", ureg->ip);
	}

	if(note.flag != NUser && (up->notified || up->notify == nil)){
		qunlock(&up->debug);
		if(note.flag == NDebug)
			pprint("suicide: %s\n", note.msg);
		pexit(note.msg, note.flag != NDebug);
	}

	if(up->notified){
		qunlock(&up->debug);
		splhi();
		return 0;
	}

	if(up->notify == nil){
		qunlock(&up->debug);
		pexit(note.msg, note.flag != NDebug);
	}
	if(!okaddr(PTR2UINT(up->notify), sizeof(ureg->ip), 0)){
		qunlock(&up->debug);
		pprint("suicide: bad function address %#p in notify\n",
			up->notify);
		pexit("Suicide", 0);
	}

	sp = ureg->sp - ROUNDUP(sizeof(NFrame), 16) - 128; // amd64 red zone, also wanted by go stack traces
	if(!okaddr(sp, sizeof(NFrame), 1)){
		qunlock(&up->debug);
		pprint("suicide: bad stack address %#p in notify\n", sp);
		pexit("Suicide", 0);
	}

	nf = UINT2PTR(sp);
	memmove(&nf->ureg, ureg, sizeof(Ureg));
	nf->old = up->ureg;
	up->ureg = nf;	/* actually the NFrame, for noted */
	memmove(nf->msg, note.msg, ERRMAX);
	nf->arg1 = nf->msg;
	nf->arg0 = &nf->ureg;
	ureg->di = (uintptr)nf->arg0;
	ureg->si = (uintptr)nf->arg1;
	//print("Setting di to %p and si to %p\n", ureg->di, ureg->si);
	ureg->bp = PTR2UINT(nf->arg0);
	nf->ip = 0;

	ureg->sp = sp;
	ureg->ip = PTR2UINT(up->notify);
	up->notified = 1;
	up->nnote--;
	memmove(&up->lastnote, &note, sizeof(Note));
	memmove(&up->note[0], &up->note[1], up->nnote*sizeof(Note));

	qunlock(&up->debug);
	splx(pl);

	return 1;
}
Exemple #5
0
/*
 *   Return user to state before notify()
 */
void
noted(Ureg* cur, uintptr_t arg0)
{
	Proc *up = externup();
	NFrame *nf;
	Note note;
	Ureg *nur;

	qlock(&up->debug);
	if(arg0 != NRSTR && !up->notified){
		qunlock(&up->debug);
		pprint("suicide: call to noted when not notified\n");
		pexit("Suicide", 0);
	}
	up->notified = 0;
	fpunoted();

	nf = up->ureg;

	/* sanity clause */
	if(!okaddr(PTR2UINT(nf), sizeof(NFrame), 0)){
		qunlock(&up->debug);
		pprint("suicide: bad ureg %#p in noted\n", nf);
		pexit("Suicide", 0);
	}

	/*
	 * Check the segment selectors are all valid.
	 */
	nur = &nf->ureg;
	if(nur->cs != SSEL(SiUCS, SsRPL3) || nur->ss != SSEL(SiUDS, SsRPL3)) {
		qunlock(&up->debug);
		pprint("suicide: bad segment selector (cs %p want %p, ss %p want %p), in noted\n",
			nur->cs, SSEL(SiUCS, SsRPL3),
			nur->ss, SSEL(SiUDS, SsRPL3)
		);
		pexit("Suicide", 0);
	}

	/* don't let user change system flags */
	nur->flags &= (Of|Df|Sf|Zf|Af|Pf|Cf);
	nur->flags |= cur->flags & ~(Of|Df|Sf|Zf|Af|Pf|Cf);

	memmove(cur, nur, sizeof(Ureg));

	switch((int)arg0){
	case NCONT:
	case NRSTR:
		if(!okaddr(nur->ip, BY2SE, 0) || !okaddr(nur->sp, BY2SE, 0)){
			qunlock(&up->debug);
			pprint("suicide: trap in noted pc=%#p sp=%#p\n",
				nur->ip, nur->sp);
			pexit("Suicide", 0);
		}
		up->ureg = nf->old;
		qunlock(&up->debug);
		break;
	case NSAVE:
		if(!okaddr(nur->ip, BY2SE, 0) || !okaddr(nur->sp, BY2SE, 0)){
			qunlock(&up->debug);
			pprint("suicide: trap in noted pc=%#p sp=%#p\n",
				nur->ip, nur->sp);
			pexit("Suicide", 0);
		}
		qunlock(&up->debug);

		splhi();
		nf->arg1 = nf->msg;
		nf->arg0 = &nf->ureg;
		cur->bp = PTR2UINT(nf->arg0);
		nf->ip = 0;
		cur->sp = PTR2UINT(nf);
		break;
	default:
		memmove(&note, &up->lastnote, sizeof(Note));
		qunlock(&up->debug);
		pprint("suicide: bad arg %#p in noted: %s\n", arg0, note.msg);
		pexit(note.msg, 0);
		break;
	case NDFLT:
		memmove(&note, &up->lastnote, sizeof(Note));
		qunlock(&up->debug);
		if(note.flag == NDebug)
			pprint("suicide: %s\n", note.msg);
		pexit(note.msg, note.flag != NDebug);
		break;
	}
}
Exemple #6
0
/*
 *  the devxxx.c that calls us handles writing data, it knows best
 */
int32_t
netifwrite(Netif *nif, Chan *c, void *a, int32_t n)
{
	Proc *up = externup();
	Netfile *f;
	int type, mtu;
	char *p, buf[64];
	uint8_t binaddr[Nmaxaddr];

	if(NETTYPE(c->qid.path) != Nctlqid)
		error(Eperm);

	if(n >= sizeof(buf))
		n = sizeof(buf)-1;
	memmove(buf, a, n);
	buf[n] = 0;

	if(waserror()){
		qunlock(nif);
		nexterror();
	}

	qlock(nif);
	f = nif->f[NETID(c->qid.path)];
	if((p = matchtoken(buf, "connect")) != 0){
		qclose(f->iq);
		type = atoi(p);
		if(typeinuse(nif, type))
			error(Einuse);
		f->type = type;
		if(f->type < 0)
			nif->all++;
		qreopen(f->iq);
	} else if(matchtoken(buf, "promiscuous")){
		if(f->prom == 0){
			if(nif->prom == 0 && nif->promiscuous != nil)
				nif->promiscuous(nif->arg, 1);
			f->prom = 1;
			nif->prom++;
		}
	} else if((p = matchtoken(buf, "scanbs")) != 0){
		/* scan for base stations */
		if(f->scan == 0){
			type = atoi(p);
			if(type < 5)
				type = 5;
			if(nif->scanbs != nil)
				nif->scanbs(nif->arg, type);
			f->scan = type;
			nif->_scan++;
		}
	} else if((p = matchtoken(buf, "mtu")) != 0){
		/* poor planning. */
		if(!iseve())
			error(Eperm);
		mtu = atoi(p);
		/* zero resets default. */
		if(mtu != 0)
		if(mtu < nif->minmtu || mtu > nif->maxmtu)
			error(Ebadarg);
		if(nif->hwmtu)
			nif->mtu = nif->hwmtu(nif->arg, mtu);
		else
			nif->mtu = mtu;
	} else if(matchtoken(buf, "l2bridge")){
		f->bridge |= 2;
	} else if(matchtoken(buf, "bridge")){
		f->bridge |= 1;
	} else if(matchtoken(buf, "headersonly")){
		f->headersonly = 1;
	} else if((p = matchtoken(buf, "addmulti")) != 0){
		if(parseaddr(binaddr, p, nif->alen) < 0)
			error("bad address");
		p = netmulti(nif, f, binaddr, 1);
		if(p)
			error(p);
	} else if((p = matchtoken(buf, "remmulti")) != 0){
		if(parseaddr(binaddr, p, nif->alen) < 0)
			error("bad address");
		p = netmulti(nif, f, binaddr, 0);
		if(p)
			error(p);
	} else
		n = -1;
	qunlock(nif);
	poperror();
	return n;
}
Exemple #7
0
/*
 * pg->pgszi indicates the page size in machp()->pgsz[] used for the mapping.
 * For the user, it can be either 2*MiB or 1*GiB pages.
 * For 2*MiB pages, we use three levels, not four.
 * For 1*GiB pages, we use two levels.
 */
void
mmuput(uintptr_t va, Page *pg, uint attr)
{
    Proc *up = externup();
    int lvl, user, x, pgsz;
    PTE *pte;
    Page *page, *prev;
    Mpl pl;
    uintmem pa, ppn;
    char buf[80];

    ppn = 0;
    pa = pg->pa;
    if(pa == 0)
        panic("mmuput: zero pa");

    if(DBGFLG) {
        snprint(buf, sizeof buf, "cpu%d: up %#p mmuput %#p %#P %#ux\n",
                machp()->machno, up, va, pa, attr);
        print("%s", buf);
    }
    assert(pg->pgszi >= 0);
    pgsz = sys->pgsz[pg->pgszi];
    if(pa & (pgsz-1))
        panic("mmuput: pa offset non zero: %#ullx\n", pa);
    pa |= pteflags(attr);

    pl = splhi();
    if(DBGFLG)
        mmuptpcheck(up);
    user = (va < KZERO);
    x = PTLX(va, 3);

    pte = UINT2PTR(machp()->MMU.pml4->va);
    pte += x;
    prev = machp()->MMU.pml4;

    for(lvl = 3; lvl >= 0; lvl--) {
        if(user) {
            if(pgsz == 2*MiB && lvl == 1)	 /* use 2M */
                break;
            if(pgsz == 1ull*GiB && lvl == 2)	/* use 1G */
                break;
        }
        for(page = up->MMU.mmuptp[lvl]; page != nil; page = page->next)
            if(page->prev == prev && page->daddr == x) {
                if(*pte == 0) {
                    print("mmu: jmk and nemo had fun\n");
                    *pte = PPN(page->pa)|PteU|PteRW|PteP;
                }
                break;
            }

        if(page == nil) {
            if(up->MMU.mmuptp[0] == nil)
                page = mmuptpalloc();
            else {
                page = up->MMU.mmuptp[0];
                up->MMU.mmuptp[0] = page->next;
            }
            page->daddr = x;
            page->next = up->MMU.mmuptp[lvl];
            up->MMU.mmuptp[lvl] = page;
            page->prev = prev;
            *pte = PPN(page->pa)|PteU|PteRW|PteP;
            if(lvl == 3 && x >= machp()->MMU.pml4->daddr)
                machp()->MMU.pml4->daddr = x+1;
        }
        x = PTLX(va, lvl-1);

        ppn = PPN(*pte);
        if(ppn == 0)
            panic("mmuput: ppn=0 l%d pte %#p = %#P\n", lvl, pte, *pte);

        pte = UINT2PTR(KADDR(ppn));
        pte += x;
        prev = page;
    }

    if(DBGFLG)
        checkpte(ppn, pte);
    *pte = pa|PteU;

    if(user)
        switch(pgsz) {
        case 2*MiB:
        case 1*GiB:
            *pte |= PtePS;
            break;
        default:
            panic("mmuput: user pages must be 2M or 1G");
        }
    splx(pl);

    if(DBGFLG) {
        snprint(buf, sizeof buf, "cpu%d: up %#p new pte %#p = %#llux\n",
                machp()->machno, up, pte, pte?*pte:~0);
        print("%s", buf);
    }

    invlpg(va);			/* only if old entry valid? */
}
Exemple #8
0
int
ipoput6(Fs *f, Block *bp, int gating, int ttl, int tos, Conv *c)
{
	Proc *up = externup();
	int medialen, len, chunk, uflen, flen, seglen, lid, offset, fragoff;
	int morefrags, blklen, rv = 0, tentative;
	uint8_t *gate, nexthdr;
	Block *xp, *nb;
	Fraghdr6 fraghdr;
	IP *ip;
	Ip6hdr *eh;
	Ipifc *ifc;
	Route *r, *sr;

	ip = f->ip;

	/* Fill out the ip header */
	eh = (Ip6hdr*)(bp->rp);

	ip->stats[OutRequests]++;

	/* Number of uint8_ts in data and ip header to write */
	len = blocklen(bp);

	tentative = iptentative(f, eh->src);
	if(tentative){
		netlog(f, Logip, "reject tx of packet with tentative src address %I\n",
			eh->src);
		goto free;
	}

	if(gating){
		chunk = nhgets(eh->ploadlen);
		if(chunk > len){
			ip->stats[OutDiscards]++;
			netlog(f, Logip, "short gated packet\n");
			goto free;
		}
		if(chunk + IP6HDR < len)
			len = chunk + IP6HDR;
	}

	if(len >= IP_MAX){
		ip->stats[OutDiscards]++;
		netlog(f, Logip, "exceeded ip max size %I\n", eh->dst);
		goto free;
	}

	r = v6lookup(f, eh->dst, c);
	if(r == nil){
//		print("no route for %I, src %I free\n", eh->dst, eh->src);
		ip->stats[OutNoRoutes]++;
		netlog(f, Logip, "no interface %I\n", eh->dst);
		rv = -1;
		goto free;
	}

	ifc = r->RouteTree.ifc;
	if(r->RouteTree.type & (Rifc|Runi))
		gate = eh->dst;
	else if(r->RouteTree.type & (Rbcast|Rmulti)) {
		gate = eh->dst;
		sr = v6lookup(f, eh->src, nil);
		if(sr && (sr->RouteTree.type & Runi))
			ifc = sr->RouteTree.ifc;
	}
	else
		gate = r->v6.gate;

	if(!gating)
		eh->vcf[0] = IP_VER6;
	eh->ttl = ttl;
	if(!gating) {
		eh->vcf[0] |= tos >> 4;
		eh->vcf[1]  = tos << 4;
	}
Exemple #9
0
static int
procgen(Chan *c, char *name, Dirtab *tab, int j, int s, Dir *dp)
{
	Proc *up = externup();
	Qid qid;
	Proc *p;
	char *ename;
	int pid, sno;
	uint32_t path, perm, len;

	if(s == DEVDOTDOT){
		mkqid(&qid, Qdir, 0, QTDIR);
		devdir(c, qid, "#p", 0, eve, 0555, dp);
		return 1;
	}

	if(c->qid.path == Qdir){
		if(s == 0){
			strcpy(up->genbuf, "trace");
			mkqid(&qid, Qtrace, -1, QTFILE);
			devdir(c, qid, up->genbuf, 0, eve, 0444, dp);
			return 1;
		}
		if(s == 1){
			strcpy(up->genbuf, "tracepids");
			mkqid(&qid, Qtracepids, -1, QTFILE);
			devdir(c, qid, up->genbuf, 0, eve, 0444, dp);
			return 1;
		}
		s -= 2;
		if(name != nil){
			/* ignore s and use name to find pid */
			pid = strtol(name, &ename, 10);
			if(pid<=0 || ename[0]!='\0')
				return -1;
			s = psindex(pid);
			if(s < 0)
				return -1;
		}
		else if(s >= conf.nproc)
			return -1;

		if((p = psincref(s)) == nil || (pid = p->pid) == 0)
			return 0;
		snprint(up->genbuf, sizeof up->genbuf, "%u", pid);
		/*
		 * String comparison is done in devwalk so
		 * name must match its formatted pid.
		 */
		if(name != nil && strcmp(name, up->genbuf) != 0)
			return -1;
		mkqid(&qid, (s+1)<<QSHIFT, pid, QTDIR);
		devdir(c, qid, up->genbuf, 0, p->user, DMDIR|0555, dp);
		psdecref(p);
		return 1;
	}
	if(c->qid.path == Qtrace){
		strcpy(up->genbuf, "trace");
		mkqid(&qid, Qtrace, -1, QTFILE);
		devdir(c, qid, up->genbuf, 0, eve, 0444, dp);
		return 1;
	}
	if(c->qid.path == Qtracepids){
		strcpy(up->genbuf, "tracepids");
		mkqid(&qid, Qtrace, -1, QTFILE);
		devdir(c, qid, up->genbuf, 0, eve, 0444, dp);
		return 1;
	}
	if(s >= nelem(procdir))
		return -1;
	if(tab)
		panic("procgen");

	tab = &procdir[s];
	path = c->qid.path&~(((1<<QSHIFT)-1));	/* slot component */

	if((p = psincref(SLOT(c->qid))) == nil)
		return -1;
	perm = tab->perm;
	if(perm == 0)
		perm = p->procmode;
	else	/* just copy read bits */
		perm |= p->procmode & 0444;

	len = tab->length;
	switch(QID(c->qid)) {
	case Qwait:
		len = p->nwait;	/* incorrect size, but >0 means there's something to read */
		break;
	case Qprofile: /* TODO(aki): test this */
		len = 0;
		for(sno = 0; sno < NSEG; sno++){
			if(p->seg[sno] != nil && (p->seg[sno]->type & SG_EXEC) != 0){
				Segment *s;
				s = p->seg[sno];
				if(s->profile)
					len += ((s->top-s->base)>>LRESPROF) * sizeof s->profile[0];
			}
		}
		break;
	}
Exemple #10
0
void
mmuinit(void)
{
	Proc *up = externup();
	uint8_t *p;
	Page *page;
	uint64_t o, pa, r, sz;

	archmmu();
	DBG("mach%d: %#p pml4 %#p npgsz %d\n", machp()->machno, m, machp()->pml4, m->npgsz);

	if(machp()->machno != 0){
		/* NIX: KLUDGE: Has to go when each mach is using
		 * its own page table
		 */
		p = UINT2PTR(m->stack);
		p += MACHSTKSZ;

		memmove(p, UINT2PTR(mach0pml4.va), PTSZ);
		machp()->pml4 = &machp()->pml4kludge;
		machp()->pml4->va = PTR2UINT(p);
		machp()->pml4->pa = PADDR(p);
		machp()->pml4->daddr = mach0pml4.daddr;	/* # of user mappings in pml4 */

		r = rdmsr(Efer);
		r |= Nxe;
		wrmsr(Efer, r);
		cr3put(machp()->pml4->pa);
		DBG("m %#p pml4 %#p\n", m, machp()->pml4);
		return;
	}

	page = &mach0pml4;
	page->pa = cr3get();
	page->va = PTR2UINT(KADDR(page->pa));

	machp()->pml4 = page;

	r = rdmsr(Efer);
	r |= Nxe;
	wrmsr(Efer, r);

	/*
	 * Set up the various kernel memory allocator limits:
	 * pmstart/pmend bound the unused physical memory;
	 * vmstart/vmend bound the total possible virtual memory
	 * used by the kernel;
	 * vmunused is the highest virtual address currently mapped
	 * and used by the kernel;
	 * vmunmapped is the highest virtual address currently
	 * mapped by the kernel.
	 * Vmunused can be bumped up to vmunmapped before more
	 * physical memory needs to be allocated and mapped.
	 *
	 * This is set up here so meminit can map appropriately.
	 */
	o = sys->pmstart;
	sz = ROUNDUP(o, 4*MiB) - o;
	pa = asmalloc(0, sz, 1, 0);
	if(pa != o)
		panic("mmuinit: pa %#llux memstart %#llux\n", pa, o);
	sys->pmstart += sz;

	sys->vmstart = KSEG0;
	sys->vmunused = sys->vmstart + ROUNDUP(o, 4*KiB);
	sys->vmunmapped = sys->vmstart + o + sz;
	sys->vmend = sys->vmstart + TMFM;

	print("mmuinit: vmstart %#p vmunused %#p vmunmapped %#p vmend %#p\n",
		sys->vmstart, sys->vmunused, sys->vmunmapped, sys->vmend);

	/*
	 * Set up the map for PD entry access by inserting
	 * the relevant PDP entry into the PD. It's equivalent
	 * to PADDR(sys->pd)|PteRW|PteP.
	 *
	 */
	sys->pd[PDX(PDMAP)] = sys->pdp[PDPX(PDMAP)] & ~(PteD|PteA);
	print("sys->pd %#p %#p\n", sys->pd[PDX(PDMAP)], sys->pdp[PDPX(PDMAP)]);
	assert((pdeget(PDMAP) & ~(PteD|PteA)) == (PADDR(sys->pd)|PteRW|PteP));


	dumpmmuwalk(KZERO);

	mmuphysaddr(PTR2UINT(end));
}
Exemple #11
0
static int32_t
pmcwrite(Chan *c, void *a, int32_t n, int64_t mm)
{
	Proc *up = externup();
	Cmdbuf *cb;
	Cmdtab *ct;
	uint32_t type;
	char str[64];	/* 0x0000000000000000\0 */
	AcPmcArg p;
	AcCtrArg ctr;
	uint64_t coreno;
	Mach *mp;

	if (c->qid.type == QTDIR)
		error(Eperm);
	if (c->qid.path == Qgctl)
		error(Eperm);
	if (n >= sizeof(str))
		error(Ebadctl);

	pmcnull(&p);
	coreno = (uint64_t)c->aux;
	p.coreno = coreno;
	type = PMCTYPE(c->qid.path);
	p.regno = PMCID(c->qid.path);
	memmove(str, a, n);
	str[n] = '\0';
	mp = up->ac;

	ctr.coreno = coreno;
	ctr.regno = p.regno;
	if (type == Qdata) {
		/* I am a handler for a proc in the core, run an RPC*/
		if (mp != nil && mp->machno == coreno) {
			if (runac(mp, acpmcsetctr, 0, &ctr, sizeof(AcCtrArg)) < 0)
				n = -1;
		} else {
		if (pmcsetctr(coreno, strtoull(str, 0, 0), p.regno) < 0)
			n = -1;
		}
		return n;
	}


	/* TODO: should iterate through multiple lines */
	if (strncmp(str, "set ", 4) == 0){
		memmove(p.descstr, (char *)str + 4, n - 4);
		p.descstr[n - 4] = '\0';
		p.nodesc = 0;
	} else {
		cb = parsecmd(a, n);
		if(waserror()){
			free(cb);
			nexterror();
		}
		ct = lookupcmd(cb, pmcctlmsg, nelem(pmcctlmsg));
		switch(ct->index){
		case Enable:
			p.enab = 1;
			break;
		case Disable:
			p.enab = 0;
			break;
		case User:
			p.user = 1;
			break;
		case Os:
			p.os = 1;
			break;
		case NoUser:
			p.user = 0;
			break;
		case NoOs:
			p.os = 0;
			break;
		case Reset:
			p.reset = 1;
			break;
		case Debug:
			pmcdebug = ~pmcdebug;
			break;
		default:
			cmderror(cb, "invalid ctl");
		break;
		}
		free(cb);
		poperror();
	}
	/* I am a handler for a proc in the core, run an RPC*/
	if (mp != nil && mp->machno == coreno) {
		if (runac(mp, acpmcsetctl, 0, &p, sizeof(AcPmcArg)) < 0)
			n = -1;
	} else {
		if (pmcsetctl(coreno, &p, p.regno) < 0)
			n = -1;
	}
	return n;
}
Exemple #12
0
int
anyhigher(void)
{
	Proc *up = externup();
	return run.runvec & ~((1<<(up->priority+1))-1);
}
Exemple #13
0
void
nexterror(void)
{
	Proc *up = externup();
	/*debug*/gotolabel(&up->errlab[--up->nerrlab]);
}
Exemple #14
0
/*
 *  If changing this routine, look also at sleep().  It
 *  contains a copy of the guts of sched().
 */
void
sched(void)
{
	Proc *up = externup();
	Proc *p;

	if(!islo() && machp()->ilockdepth)
		panic("cpu%d: ilockdepth %d, last lock %#p at %#p, sched called from %#p",
			machp()->machno,
			machp()->ilockdepth,
			up? up->lastilock: nil,
			(up && up->lastilock)? up->lastilock->_pc: 0,
			getcallerpc());

	kstackok();
	if(up){
		/*
		 * Delay the sched until the process gives up the locks
		 * it is holding.  This avoids dumb lock loops.
		 * Don't delay if the process is Moribund.
		 * It called sched to die.
		 * But do sched eventually.  This avoids a missing unlock
		 * from hanging the entire kernel.
		 * But don't reschedule procs holding palloc or procalloc.
		 * Those are far too important to be holding while asleep.
		 *
		 * This test is not exact.  There can still be a few
		 * instructions in the middle of taslock when a process
		 * holds a lock but Lock.p has not yet been initialized.
		 */
		if(up->nlocks)
		if(up->state != Moribund)
		if(up->delaysched < 20
		|| pga.l.p == up
		|| procalloc.l.p == up){
			up->delaysched++;
 			run.delayedscheds++;
			return;
		}
		up->delaysched = 0;

		splhi();
		/* statistics */
		if(up->nqtrap == 0 && up->nqsyscall == 0)
			up->nfullq++;
		machp()->cs++;

		procsave(up);
		mmuflushtlb(machp()->MMU.pml4->pa);
		if(setlabel(&up->sched)){
			procrestore(up);
			spllo();
			return;
		}
		/*debug*/gotolabel(&machp()->sched);
	}

	machp()->inidle = 1;
	p = runproc();	/* core 0 never returns */
	machp()->inidle = 0;

	if(!p->edf){
		updatecpu(p);
		p->priority = reprioritize(p);
	}
	if(nosmp){
		if(p != machp()->readied)
			machp()->schedticks = machp()->ticks + HZ/10;
		machp()->readied = 0;
	}
	machp()->externup = p;
	up = p;
	machp()->qstart = machp()->ticks;
	up->nqtrap = 0;
	up->nqsyscall = 0;
	up->state = Running;
	//up->mach = m;
	up->mach = sys->machptr[machp()->machno];
	machp()->proc = up;
//	iprint("up->sched.sp %p * %p\n", up->sched.sp,
//		*(void **) up->sched.sp);
	mmuswitch(up);

	assert(!up->wired || up->wired == machp());
	if (0) hi("gotolabel\n");
	/*debug*/gotolabel(&up->sched);
}
Exemple #15
0
/*
 * Zero copy I/O.
 * I/O is performed using an array of Zio structures.
 * Each one points to a shared buffer address indicating a length.
 * Each entry indicating a length and using nil as the address
 * is asking the system to allocate memory as needed (mread only).
 */
static int
ziorw(int fd, Zio *io, int nio, usize count, int64_t offset, int iswrite)
{
	Proc *up = externup();
	int i, n, isprw;
	Kzio *kio, skio[16];
	Chan *c;
	usize tot;

	if(nio <= 0 || nio > 512)
		error("wrong io[] size");
	zioinit();
	kio = nil;

	io = validaddr(io, sizeof io[0] * nio, 1);
	DBG("ziorw %d io%#p[%d] %lu %lld\n", fd, io, nio, count, offset);
	if(DBGFLG)
		for(i = 0; i < nio; i++)
			print("\tio%#p[%d] = %Z %s\n",
				io, i, (Kzio*)&io[i], iswrite?"w":"r");

	if(iswrite)
		c = fdtochan(fd, OWRITE, 1, 1);
	else
		c = fdtochan(fd, OREAD, 1, 1);
	isprw = offset != -1LL;
	if(isprw)
		offset = c->offset;
	if(waserror()){
		cclose(c);
		if(kio != nil){
			for(i = 0; i < nio; i++)
				if(kio[i].seg != nil)
					putseg(kio[i].seg);
			if(kio != skio)
				free(kio);
		}
		nexterror();
	}
	if(nio < nelem(skio))
		kio = skio;
	else
		kio = smalloc(sizeof kio[0] * nio);
	for(i = 0; i < nio; i++){
		kio[i].Zio = io[i];
		if(iswrite){
			kio[i].seg = seg(up, PTR2UINT(io[i].data), 1);
			if(kio[i].seg == nil)
				error("invalid address in zio");
			incref(&kio[i].seg->r);
			qunlock(&kio[i].seg->lk);
			validaddr(kio[i].Zio.data, kio[i].Zio.size, 1);
			if((kio[i].seg->type&SG_ZIO) == 0){
				/*
				 * It's not a segment where we can report
				 * addresses to anyone once they are free.
				 * So, allocate space in the kernel
				 * and copy the user data there.
				 */
				kernzio(&kio[i]);
			}
			assert(kio[i].seg->type&SG_ZIO);
		}else{
			kio[i].Zio.data = nil;
			kio[i].seg = nil;
		}
	}

	if(c->dev->zread == nil){
		DBG("installing devzread for %s\n", c->dev->name);
		c->dev->zread = devzread;
	}
	if(c->dev->zwrite == nil){
		DBG("installing devzwrite for %s\n", c->dev->name);
		c->dev->zwrite = devzwrite;
	}
	if(iswrite)
		n = c->dev->zwrite(c, kio, nio, offset);
	else
		n = c->dev->zread(c, kio, nio, count, offset);
	tot = 0;
	for(i = 0; i < n; i++){
		io[i] = kio[i].Zio;
		tot += kio[i].Zio.size;
	}
	if(!isprw){
		/* unlike in syswrite, we update offsets at the end */
		lock(&c->r.l);
		c->devoffset += tot;
		c->offset += tot;
		unlock(&c->r.l);
	}
	poperror();
	cclose(c);
	if(kio != skio)
		free(kio);
	return n;
}
Exemple #16
0
/*
 *  All traps come here.  It is slower to have all traps call trap()
 *  rather than directly vectoring the handler.  However, this avoids a
 *  lot of code duplication and possible bugs.  The only exception is
 *  VectorSYSCALL.
 *  Trap is called with interrupts disabled via interrupt-gates.
 */
void
trap(Ureg* ureg)
{
    int clockintr, vno, user;
    // cache the previous vno to see what might be causing
    // trouble
    vno = ureg->type;
    uint64_t gsbase = rdmsr(GSbase);
    //if (sce > scx) iprint("====================");
    lastvno = vno;
    if (gsbase < 1ULL<<63)
        die("bogus gsbase");
    Proc *up = externup();
    char buf[ERRMAX];
    Vctl *ctl, *v;

    machp()->perf.intrts = perfticks();
    user = userureg(ureg);
    if(user && (machp()->NIX.nixtype == NIXTC)) {
        up->dbgreg = ureg;
        cycles(&up->kentry);
    }

    clockintr = 0;

    //_pmcupdate(machp());

    if(ctl = vctl[vno]) {
        if(ctl->isintr) {
            machp()->intr++;
            if(vno >= VectorPIC && vno != VectorSYSCALL)
                machp()->lastintr = ctl->Vkey.irq;
        } else if(up)
            up->nqtrap++;

        if(ctl->isr) {
            ctl->isr(vno);
            if(islo())print("trap %d: isr %p enabled interrupts\n", vno, ctl->isr);
        }
        for(v = ctl; v != nil; v = v->next) {
            if(v->f) {
                v->f(ureg, v->a);
                if(islo())print("trap %d: ctlf %p enabled interrupts\n", vno, v->f);
            }
        }
        if(ctl->eoi) {
            ctl->eoi(vno);
            if(islo())print("trap %d: eoi %p enabled interrupts\n", vno, ctl->eoi);
        }

        intrtime(vno);
        if(ctl->isintr) {
            if(ctl->Vkey.irq == IrqCLOCK || ctl->Vkey.irq == IrqTIMER)
                clockintr = 1;

            if (ctl->Vkey.irq == IrqTIMER)
                oprof_alarm_handler(ureg);

            if(up && !clockintr)
                preempted();
        }
    }
    else if(vno < nelem(excname) && user) {
        spllo();
        snprint(buf, sizeof buf, "sys: trap: %s", excname[vno]);
        postnote(up, 1, buf, NDebug);
    }
    else if(vno >= VectorPIC && vno != VectorSYSCALL) {
        /*
         * An unknown interrupt.
         * Check for a default IRQ7. This can happen when
         * the IRQ input goes away before the acknowledge.
         * In this case, a 'default IRQ7' is generated, but
         * the corresponding bit in the ISR isn't set.
         * In fact, just ignore all such interrupts.
         */

        /* clear the interrupt */
        i8259isr(vno);

        iprint("cpu%d: spurious interrupt %d, last %d\n",
               machp()->machno, vno, machp()->lastintr);
        intrtime(vno);
        if(user)
            kexit(ureg);
        return;
    }
    else {
        if(vno == VectorNMI) {
            nmienable();
            if(machp()->machno != 0) {
                iprint("cpu%d: PC %#llx\n",
                       machp()->machno, ureg->ip);
                for(;;);
            }
        }
        dumpregs(ureg);
        if(!user) {
            ureg->sp = PTR2UINT(&ureg->sp);
            dumpstackwithureg(ureg);
        }
        if(vno < nelem(excname))
            panic("%s", excname[vno]);
        panic("unknown trap/intr: %d\n", vno);
    }
    splhi();

    /* delaysched set because we held a lock or because our quantum ended */
    if(up && up->delaysched && clockintr) {
        if(0)
            if(user && up->ac == nil && up->nqtrap == 0 && up->nqsyscall == 0) {
                if(!waserror()) {
                    up->ac = getac(up, -1);
                    poperror();
                    runacore();
                    return;
                }
            }
        sched();
        splhi();
    }


    if(user) {
        if(up && up->procctl || up->nnote)
            notify(ureg);
        kexit(ureg);
    }
}
Exemple #17
0
int32_t
netifread(Netif *nif, Chan *c, void *a, int32_t n, int64_t off)
{
	Proc *up = externup();
	int i, j;
	Netfile *f;
	char *p;
	int32_t offset;

	if(c->qid.type & QTDIR)
		return devdirread(c, a, n, (Dirtab*)nif, 0, netifgen);

	offset = off;
	switch(NETTYPE(c->qid.path)){
	case Ndataqid:
		f = nif->f[NETID(c->qid.path)];
		return qread(f->iq, a, n);
	case Nctlqid:
		return readnum(offset, a, n, NETID(c->qid.path), NUMSIZE);
	case Nstatqid:
		p = malloc(READSTR);
		if(p == nil)
			error(Enomem);
		j = snprint(p, READSTR, "in: %llud\n", nif->inpackets);
		j += snprint(p+j, READSTR-j, "link: %d\n", nif->link);
		j += snprint(p+j, READSTR-j, "out: %llud\n", nif->outpackets);
		j += snprint(p+j, READSTR-j, "crc errs: %llud\n", nif->crcs);
		j += snprint(p+j, READSTR-j, "overflows: %llud\n", nif->overflows);
		j += snprint(p+j, READSTR-j, "soft overflows: %llud\n", nif->soverflows);
		j += snprint(p+j, READSTR-j, "framing errs: %llud\n", nif->frames);
		j += snprint(p+j, READSTR-j, "buffer errs: %llud\n", nif->buffs);
		j += snprint(p+j, READSTR-j, "output errs: %llud\n", nif->oerrs);
		j += snprint(p+j, READSTR-j, "prom: %d\n", nif->prom);
		j += snprint(p+j, READSTR-j, "mbps: %d\n", nif->mbps);
		j += snprint(p+j, READSTR-j, "addr: ");
		for(i = 0; i < nif->alen; i++)
			j += snprint(p+j, READSTR-j, "%2.2ux", nif->addr[i]);
		snprint(p+j, READSTR-j, "\n");
		n = readstr(offset, a, n, p);
		free(p);
		return n;
	case Naddrqid:
		p = malloc(READSTR);
		j = 0;
		for(i = 0; i < nif->alen; i++)
			j += snprint(p+j, READSTR-j, "%2.2ux", nif->addr[i]);
		n = readstr(offset, a, n, p);
		free(p);
		return n;
	case Ntypeqid:
		f = nif->f[NETID(c->qid.path)];
		return readnum(offset, a, n, f->type, NUMSIZE);
	case Nifstatqid:
		return 0;
	case Nmtuqid:
		snprint(up->genbuf, sizeof up->genbuf, "%11.ud %11.ud %11.ud\n", nif->minmtu, nif->mtu, nif->maxmtu);
		return readstr(offset, a, n, up->genbuf);
	}
	error(Ebadarg);
	return -1;	/* not reached */
}
Exemple #18
0
void
asmmeminit(void)
{
    Proc *up = externup();
    int i, l;
    Asm* assem;
    PTE *pte, *pml4;
    uintptr va;
    uintmem hi, lo, mem, nextmem, pa;
#ifdef ConfCrap
    int cx;
#endif /* ConfCrap */

    assert(!((sys->vmunmapped|sys->vmend) & machp()->pgszmask[1]));

    if((pa = mmuphysaddr(sys->vmunused)) == ~0)
        panic("asmmeminit 1");
    pa += sys->vmunmapped - sys->vmunused;
    mem = asmalloc(pa, sys->vmend - sys->vmunmapped, 1, 0);
    if(mem != pa)
        panic("asmmeminit 2");
    DBG("pa %#llux mem %#llux\n", pa, mem);

    /* assume already 2MiB aligned*/
    assert(ALIGNED(sys->vmunmapped, 2*MiB));
    pml4 = UINT2PTR(machp()->pml4->va);
    while(sys->vmunmapped < sys->vmend) {
        l = mmuwalk(pml4, sys->vmunmapped, 1, &pte, asmwalkalloc);
        DBG("%#p l %d\n", sys->vmunmapped, l);
        *pte = pa|PtePS|PteRW|PteP;
        sys->vmunmapped += 2*MiB;
        pa += 2*MiB;
    }

#ifdef ConfCrap
    cx = 0;
#endif /* ConfCrap */
    for(assem = asmlist; assem != nil; assem = assem->next) {
        if(assem->type != AsmMEMORY)
            continue;
        va = KSEG2+assem->addr;
        print("asm: addr %#P end %#P type %d size %P\n",
              assem->addr, assem->addr+assem->size,
              assem->type, assem->size);

        lo = assem->addr;
        hi = assem->addr+assem->size;
        /* Convert a range into pages */
        for(mem = lo; mem < hi; mem = nextmem) {
            nextmem = (mem + PGLSZ(0)) & ~machp()->pgszmask[0];

            /* Try large pages first */
            for(i = m->npgsz - 1; i >= 0; i--) {
                if((mem & machp()->pgszmask[i]) != 0)
                    continue;
                if(mem + PGLSZ(i) > hi)
                    continue;
                /* This page fits entirely within the range. */
                /* Mark it a usable */
                if((l = mmuwalk(pml4, va, i, &pte, asmwalkalloc)) < 0)
                    panic("asmmeminit 3");

                *pte = mem|PteRW|PteP;
                if(l > 0)
                    *pte |= PtePS;

                nextmem = mem + PGLSZ(i);
                va += PGLSZ(i);
                npg[i]++;

                break;
            }
        }

#ifdef ConfCrap
        /*
         * Fill in conf crap.
         */
        if(cx >= nelem(conf.mem))
            continue;
        lo = ROUNDUP(assem->addr, PGSZ);
//if(lo >= 600ull*MiB)
//    continue;
        conf.mem[cx].base = lo;
        hi = ROUNDDN(hi, PGSZ);
//if(hi > 600ull*MiB)
//  hi = 600*MiB;
        conf.mem[cx].npage = (hi - lo)/PGSZ;
        conf.npage += conf.mem[cx].npage;
        print("cm %d: addr %#llux npage %lud\n",
              cx, conf.mem[cx].base, conf.mem[cx].npage);
        cx++;
#endif /* ConfCrap */
    }
    print("%d %d %d\n", npg[0], npg[1], npg[2]);

#ifdef ConfCrap
    /*
     * Fill in more conf crap.
     * This is why I hate Plan 9.
     */
    conf.upages = conf.npage;
    i = (sys->vmend - sys->vmstart)/PGSZ;		/* close enough */
    conf.ialloc = (i/2)*PGSZ;
    print("npage %llud upage %lud kpage %d\n",
          conf.npage, conf.upages, i);

#endif /* ConfCrap */
}
Exemple #19
0
/*
 *  generate a 3 level directory
 */
static int
netifgen(Chan *c, char* j, Dirtab *vp, int n, int i, Dir *dp)
{
	Proc *up = externup();
	Qid q;
	Netif *nif = (Netif*)vp;
	Netfile *f;
	int t;
	int perm;
	char *o;

	q.type = QTFILE;
	q.vers = 0;

	/* top level directory contains the name of the network */
	if(c->qid.path == 0){
		switch(i){
		case DEVDOTDOT:
			q.path = 0;
			q.type = QTDIR;
			devdir(c, q, ".", 0, eve, 0555, dp);
			break;
		case 0:
			q.path = N2ndqid;
			q.type = QTDIR;
			strcpy(up->genbuf, nif->name);
			devdir(c, q, up->genbuf, 0, eve, 0555, dp);
			break;
		default:
			return -1;
		}
		return 1;
	}

	/* second level contains clone plus all the conversations */
	t = NETTYPE(c->qid.path);
	if(t == N2ndqid || t == Ncloneqid || t == Naddrqid
	|| t == Nstatqid || t == Nifstatqid || t == Nmtuqid){
		switch(i) {
		case DEVDOTDOT:
			q.type = QTDIR;
			q.path = 0;
			devdir(c, q, ".", 0, eve, DMDIR|0555, dp);
			break;
		case 0:
			q.path = Ncloneqid;
			devdir(c, q, "clone", 0, eve, 0666, dp);
			break;
		case 1:
			q.path = Naddrqid;
			devdir(c, q, "addr", 0, eve, 0666, dp);
			break;
		case 2:
			q.path = Nstatqid;
			devdir(c, q, "stats", 0, eve, 0444, dp);
			break;
		case 3:
			q.path = Nifstatqid;
			devdir(c, q, "ifstats", 0, eve, 0444, dp);
			break;
		case 4:
			q.path = Nmtuqid;
			devdir(c, q, "mtu", 0, eve, 0444, dp);
			break;
		default:
			i -= 5;
			if(i >= nif->nfile)
				return -1;
			if(nif->f[i] == 0)
				return 0;
			q.type = QTDIR;
			q.path = NETQID(i, N3rdqid);
			snprint(up->genbuf, sizeof up->genbuf, "%d", i);
			devdir(c, q, up->genbuf, 0, eve, DMDIR|0555, dp);
			break;
		}
		return 1;
	}

	/* third level */
	f = nif->f[NETID(c->qid.path)];
	if(f == 0)
		return 0;
	if(*f->owner){
		o = f->owner;
		perm = f->mode;
	} else {
		o = eve;
		perm = 0666;
	}
	switch(i){
	case DEVDOTDOT:
		q.type = QTDIR;
		q.path = N2ndqid;
		strcpy(up->genbuf, nif->name);
		devdir(c, q, up->genbuf, 0, eve, DMDIR|0555, dp);
		break;
	case 0:
		q.path = NETQID(NETID(c->qid.path), Ndataqid);
		devdir(c, q, "data", 0, o, perm, dp);
		break;
	case 1:
		q.path = NETQID(NETID(c->qid.path), Nctlqid);
		devdir(c, q, "ctl", 0, o, perm, dp);
		break;
	case 2:
		q.path = NETQID(NETID(c->qid.path), Nstatqid);
		devdir(c, q, "stats", 0, eve, 0444, dp);
		break;
	case 3:
		q.path = NETQID(NETID(c->qid.path), Ntypeqid);
		devdir(c, q, "type", 0, eve, 0444, dp);
		break;
	case 4:
		q.path = NETQID(NETID(c->qid.path), Nifstatqid);
		devdir(c, q, "ifstats", 0, eve, 0444, dp);
		break;
	default:
		return -1;
	}
	return 1;
}
Exemple #20
0
void
rudpkick(void *x)
{
	Proc *up = externup();
	Conv *c = x;
	Udphdr *uh;
	uint16_t rport;
	uint8_t laddr[IPaddrlen], raddr[IPaddrlen];
	Block *bp;
	Rudpcb *ucb;
	Rudphdr *rh;
	Reliable *r;
	int dlen, ptcllen;
	Rudppriv *upriv;
	Fs *f;

	upriv = c->p->priv;
	f = c->p->f;

	netlog(c->p->f, Logrudp, "rudp: kick\n");
	bp = qget(c->wq);
	if(bp == nil)
		return;

	ucb = (Rudpcb*)c->ptcl;
	switch(ucb->headers) {
	case 7:
		/* get user specified addresses */
		bp = pullupblock(bp, UDP_USEAD7);
		if(bp == nil)
			return;
		ipmove(raddr, bp->rp);
		bp->rp += IPaddrlen;
		ipmove(laddr, bp->rp);
		bp->rp += IPaddrlen;
		/* pick interface closest to dest */
		if(ipforme(f, laddr) != Runi)
			findlocalip(f, laddr, raddr);
		bp->rp += IPaddrlen;		/* Ignore ifc address */
		rport = nhgets(bp->rp);
		bp->rp += 2+2;			/* Ignore local port */
		break;
	default:
		ipmove(raddr, c->raddr);
		ipmove(laddr, c->laddr);
		rport = c->rport;
		break;
	}

	dlen = blocklen(bp);

	/* Make space to fit rudp & ip header */
	bp = padblock(bp, UDP_IPHDR+UDP_RHDRSIZE);
	if(bp == nil)
		return;

	uh = (Udphdr *)(bp->rp);
	uh->vihl = IP_VER4;

	rh = (Rudphdr*)uh;

	ptcllen = dlen + (UDP_RHDRSIZE-UDP_PHDRSIZE);
	uh->Unused = 0;
	uh->udpproto = IP_UDPPROTO;
	uh->frag[0] = 0;
	uh->frag[1] = 0;
	hnputs(uh->udpplen, ptcllen);
	switch(ucb->headers){
	case 7:
		v6tov4(uh->udpdst, raddr);
		hnputs(uh->udpdport, rport);
		v6tov4(uh->udpsrc, laddr);
		break;
	default:
		v6tov4(uh->udpdst, c->raddr);
		hnputs(uh->udpdport, c->rport);
		if(ipcmp(c->laddr, IPnoaddr) == 0)
			findlocalip(f, c->laddr, c->raddr);
		v6tov4(uh->udpsrc, c->laddr);
		break;
	}
	hnputs(uh->udpsport, c->lport);
	hnputs(uh->udplen, ptcllen);
	uh->udpcksum[0] = 0;
	uh->udpcksum[1] = 0;

	qlock(&ucb->ql);
	r = relstate(ucb, raddr, rport, "kick");
	r->sndseq = NEXTSEQ(r->sndseq);
	hnputl(rh->relseq, r->sndseq);
	hnputl(rh->relsgen, r->sndgen);

	hnputl(rh->relack, r->rcvseq);  /* ACK last rcvd packet */
	hnputl(rh->relagen, r->rcvgen);

	if(r->rcvseq != r->acksent)
		r->acksent = r->rcvseq;

	hnputs(uh->udpcksum, ptclcsum(bp, UDP_IPHDR, dlen+UDP_RHDRSIZE));

	relackq(r, bp);
	qunlock(&ucb->ql);

	upriv->ustats.rudpOutDatagrams++;

	DPRINT("sent: %lud/%lud, %lud/%lud\n",
		r->sndseq, r->sndgen, r->rcvseq, r->rcvgen);

	doipoput(c, f, bp, 0, c->ttl, c->tos);

	if(waserror()) {
		relput(r);
		qunlock(&r->lock);
		nexterror();
	}

	/* flow control of sorts */
	qlock(&r->lock);
	if(UNACKED(r) > Maxunacked){
		r->blocked = 1;
		sleep(&r->vous, flow, r);
		r->blocked = 0;
	}

	qunlock(&r->lock);
	relput(r);
	poperror();
}
Exemple #21
0
/*
 *  attach a device (or pkt driver) to the interface.
 *  called with c locked
 */
static char*
ipifcbind(Conv *c, char **argv, int argc)
{
	Proc *up = externup();
	Ipifc *ifc;
	Medium *medium;

	if(argc < 2)
		return Ebadarg;

	ifc = (Ipifc*)c->ptcl;

	/* bind the device to the interface */
	medium = ipfindmedium(argv[1]);
	if(medium == nil)
		return "unknown interface type";

	wlock(ifc);
	if(ifc->medium != nil){
		wunlock(ifc);
		return "interface already bound";
	}
	if(waserror()){
		wunlock(ifc);
		nexterror();
	}

	/* do medium specific binding */
	(*medium->bind)(ifc, argc, argv);

	/* set the bound device name */
	if(argc > 2)
		strncpy(ifc->dev, argv[2], sizeof(ifc->dev));
	else
		snprint(ifc->dev, sizeof ifc->dev, "%s%d", medium->name, c->x);
	ifc->dev[sizeof(ifc->dev)-1] = 0;

	/* set up parameters */
	ifc->medium = medium;
	ifc->mintu = ifc->medium->mintu;
	ifc->maxtu = ifc->medium->maxtu;
	if(ifc->medium->unbindonclose == 0)
		ifc->conv->inuse++;
	ifc->rp.mflag = 0;		/* default not managed */
	ifc->rp.oflag = 0;
	ifc->rp.maxraint = 600000;	/* millisecs */
	ifc->rp.minraint = 200000;
	ifc->rp.linkmtu = 0;		/* no mtu sent */
	ifc->rp.reachtime = 0;
	ifc->rp.rxmitra = 0;
	ifc->rp.ttl = MAXTTL;
	ifc->rp.routerlt = 3 * ifc->rp.maxraint;

	/* any ancillary structures (like routes) no int32_ter pertain */
	ifc->ifcid++;

	/* reopen all the queues closed by a previous unbind */
	qreopen(c->rq);
	qreopen(c->eq);
	qreopen(c->sq);

	wunlock(ifc);
	poperror();

	return nil;
}
Exemple #22
0
Walkqid*
devwalk(Chan *c, Chan *nc, char **name, int nname, Dirtab *tab, int ntab,
	Devgen *gen)
{
	Proc *up = externup();
	if (0) print_func_entry();
	int i, j, alloc;
	Walkqid *wq;
	char *n;
	Dir dir;

	if(nname > 0)
		isdir(c);

	if (0)
	{ int i; iprint("%d names:", nname); for(i = 0; i < nname; i++) iprint("%s ", name[i]); iprint("\n");}
	alloc = 0;
	wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid));
	if(waserror()){
		if(alloc && wq->clone!=nil)
			cclose(wq->clone);
		free(wq);
		if (0) print_func_exit();
		return nil;
	}
	if(nc == nil){
		nc = devclone(c);
		/*
		 * nc->dev remains nil for now.		//XDYNX
		 */
		alloc = 1;
	}
	wq->clone = nc;

	for(j=0; j<nname; j++){
		if(!(nc->qid.type & QTDIR)){
			if(j==0)
				error(Enotdir);
			goto Done;
		}
		n = name[j];
		if(strcmp(n, ".") == 0){
    Accept:
			wq->qid[wq->nqid++] = nc->qid;
			continue;
		}
		if(strcmp(n, "..") == 0){
			/*
			 * Use c->dev->name in the error because
			 * nc->dev should be nil here.
			 */
			if((*gen)(nc, nil, tab, ntab, DEVDOTDOT, &dir) != 1){
				print("devgen walk .. in dev%s %#llx broken\n",
					c->dev->name, nc->qid.path);
				error("broken devgen");
			}
			nc->qid = dir.qid;
			goto Accept;
		}
		/*
		 * Ugly problem: If we're using devgen, make sure we're
		 * walking the directory itself, represented by the first
		 * entry in the table, and not trying to step into a sub-
		 * directory of the table, e.g. /net/net. Devgen itself
		 * should take care of the problem, but it doesn't have
		 * the necessary information (that we're doing a walk).
		 */
		if(gen==devgen && nc->qid.path!=tab[0].qid.path)
			goto Notfound;
		for(i=0;; i++) {
			switch((*gen)(nc, n, tab, ntab, i, &dir)){
			case -1:
			Notfound:
				if(j == 0)
					error(Enonexist);
				kstrcpy(up->errstr, Enonexist, ERRMAX);
				goto Done;
			case 0:
				continue;
			case 1:
				if(strcmp(n, dir.name) == 0){
					nc->qid = dir.qid;
					goto Accept;
				}
				continue;
			}
		}
	}
	/*
	 * We processed at least one name, so will return some data.
	 * If we didn't process all nname entries succesfully, we drop
	 * the cloned channel and return just the Qids of the walks.
	 */
Done:
	poperror();
	if(wq->nqid < nname){
		if(alloc)
			cclose(wq->clone);
		wq->clone = nil;
	}else if(wq->clone){
		/* attach cloned channel to same device */
//what goes here:					//XDYNX
// ->dev must be nil because can't walk an open chan, right?
// what about ref count on dev?
		wq->clone->dev = c->dev;
		//if(wq->clone->dev)			//XDYNX
		//	devtabincr(wq->clone->dev);
	}
	if (0) print_func_exit();
	return wq;
}
Exemple #23
0
/* it should be unsigned. FIXME */
void
syscall(int badscallnr, Ureg *ureg)
{
	// can only handle 4 args right now.
	uintptr_t a0, a1, a2, a3;
	uintptr_t a4, a5 = 0;

	a0 = ureg->di;
	a1 = ureg->si;
	a2 = ureg->dx;
	a3 = ureg->r10;
	a4 = ureg->r8;
	Proc *up = externup();
	unsigned int scallnr = (unsigned int) badscallnr;
	if (0) iprint("Syscall %d, %lx, %lx, %lx %lx %lx\n", scallnr, a0, a1, a2, a3, a4);
	char *e;
	uintptr_t	sp;
	int s;
	int64_t startns, stopns;
	Ar0 ar0;
	static Ar0 zar0;

	if(!userureg(ureg))
		panic("syscall: cs %#llux\n", ureg->cs);

	cycles(&up->kentry);

	machp()->syscall++;
	up->nsyscall++;
	up->nqsyscall++;
	up->insyscall = 1;
	up->pc = ureg->ip;
	up->dbgreg = ureg;
	sp = ureg->sp;
	startns = 0;
	if (0) hi("so far syscall!\n");
	if (printallsyscalls) {
		syscallfmt(scallnr, a0, a1, a2, a3, a4, a5);
		if(up->syscalltrace) {
			print("E %s\n", up->syscalltrace);
			free(up->syscalltrace);
			up->syscalltrace = nil;
		}
	}

	if(up->procctl == Proc_tracesyscall){
		/*
		 * Redundant validaddr.  Do we care?
		 * Tracing syscalls is not exactly a fast path...
		 * Beware, validaddr currently does a pexit rather
		 * than an error if there's a problem; that might
		 * change in the future.
		 */
		if(sp < (USTKTOP-BIGPGSZ) || sp > (USTKTOP-sizeof(up->arg)-BY2SE))
			validaddr(UINT2PTR(sp), sizeof(up->arg)+BY2SE, 0);

		syscallfmt(scallnr, a0, a1, a2, a3, a4, a5);
		up->procctl = Proc_stopme;
		procctl(up);
		if(up->syscalltrace)
			free(up->syscalltrace);
		up->syscalltrace = nil;
		startns = todget(nil);
	}
	if (0) hi("more syscall!\n");
	up->scallnr = scallnr;
	if(scallnr == RFORK)
		fpusysrfork(ureg);
	spllo();

	sp = ureg->sp;
	up->nerrlab = 0;
	ar0 = zar0;
	if(!waserror()){
		if(scallnr >= nsyscall || systab[scallnr].f == nil){
			pprint("bad sys call number %d pc %#llux\n",
				scallnr, ureg->ip);
			postnote(up, 1, "sys: bad sys call", NDebug);
			error(Ebadarg);
		}

		if(sp < (USTKTOP-BIGPGSZ) || sp > (USTKTOP-sizeof(up->arg)-BY2SE))
			validaddr(UINT2PTR(sp), sizeof(up->arg)+BY2SE, 0);

		memmove(up->arg, UINT2PTR(sp+BY2SE), sizeof(up->arg));
		up->psstate = systab[scallnr].n;
	if (0) hi("call syscall!\n");
		systab[scallnr].f(&ar0, a0, a1, a2, a3, a4, a5);
	if (0) hi("it returned!\n");
		if(scallnr == SYSR1){
			/*
			 * BUG: must go when ron binaries go.
			 * NIX: Returning from execac().
			 * This means that the process is back to the
			 * time sharing core. However, the process did
			 * already return from the system call, when dispatching
			 * the user code to the AC. The only thing left is to
			 * return. The user registers should be ok, because
			 * up->dbgreg has been the user context for the process.
			 */
			return;
		}
		poperror();
	}
	else{
		/* failure: save the error buffer for errstr */
		e = up->syserrstr;
		up->syserrstr = up->errstr;
		up->errstr = e;
		if(DBGFLG && up->pid == 1)
			iprint("%s: syscall %s error %s\n",
				up->text, systab[scallnr].n, up->syserrstr);
		ar0 = systab[scallnr].r;
	}

	/*
	 * NIX: for the execac() syscall, what follows is done within
	 * the system call, because it never returns.
	 * See acore.c:/^retfromsyscall
	 */

	noerrorsleft();

	/*
	 * Put return value in frame.
	 */
	ureg->ax = ar0.p;

	if (printallsyscalls) {
		stopns = todget(nil);
		sysretfmt(scallnr, &ar0, startns, stopns, a0, a1, a2, a3, a4, a5);
		if(up->syscalltrace) {
			print("X %s\n", up->syscalltrace);
			free(up->syscalltrace);
			up->syscalltrace = nil;
		}
	}

	if(up->procctl == Proc_tracesyscall){
		stopns = todget(nil);
		up->procctl = Proc_stopme;
		sysretfmt(scallnr, &ar0, startns, stopns, a0, a1, a2, a3, a4, a5);
		s = splhi();
		procctl(up);
		splx(s);
		if(up->syscalltrace)
			free(up->syscalltrace);
		up->syscalltrace = nil;
	}else if(up->procctl == Proc_totc || up->procctl == Proc_toac)
		procctl(up);

	if (0) hi("past sysretfmt\n");
	up->insyscall = 0;
	up->psstate = 0;

	if(scallnr == NOTED)
		noted(ureg, a0);

	if (0) hi("now to splhi\n");
	splhi();
	if(scallnr != RFORK && (up->procctl || up->nnote))
		notify(ureg);

	/* if we delayed sched because we held a lock, sched now */
	if(up->delaysched){
		sched();
		splhi();
	}
	kexit(ureg);
	if (0) hi("done kexit\n");
}
Exemple #24
0
static int32_t
vgaread(Chan* c, void* a, int32_t n, int64_t off)
{
	Proc *up = externup();
	int len;
	char *p, *s;
	VGAscr *scr;
	uint32_t offset = off;
	char chbuf[30];

	switch((uint32_t)c->qid.path){

	case Qdir:
		return devdirread(c, a, n, vgadir, nelem(vgadir), devgen);

	case Qvgabios:
		if(offset >= 0x100000)
			return 0;
		if(offset+n >= 0x100000)
			n = 0x100000 - offset;
		memmove(a, (unsigned char*)KADDR(0)+offset, n);
		return n;

	case Qvgactl:
		scr = &vgascreen[0];

		p = malloc(READSTR);
		if(p == nil)
			error(Enomem);
		if(waserror()){
			free(p);
			nexterror();
		}

		len = 0;

		if(scr->dev)
			s = scr->dev->name;
		else
			s = "cga";
		len += snprint(p+len, READSTR-len, "type %s\n", s);

		if(scr->gscreen) {
			len += snprint(p+len, READSTR-len, "size %dx%dx%d %s\n",
				scr->gscreen->r.max.x, scr->gscreen->r.max.y,
				scr->gscreen->depth, chantostr(chbuf, scr->gscreen->chan));

			if(Dx(scr->gscreen->r) != Dx(physgscreenr) 
			|| Dy(scr->gscreen->r) != Dy(physgscreenr))
				len += snprint(p+len, READSTR-len, "actualsize %dx%d\n",
					physgscreenr.max.x, physgscreenr.max.y);
		}

		len += snprint(p+len, READSTR-len, "blank time %lu idle %d state %s\n",
			blanktime, drawidletime(), scr->isblank ? "off" : "on");
		len += snprint(p+len, READSTR-len, "hwaccel %s\n", hwaccel ? "on" : "off");
		len += snprint(p+len, READSTR-len, "hwblank %s\n", hwblank ? "on" : "off");
		len += snprint(p+len, READSTR-len, "panning %s\n", panning ? "on" : "off");
		len += snprint(p+len, READSTR-len, "addr p 0x%lx v 0x%p size 0x%x\n", scr->paddr, scr->vaddr, scr->apsize);
		USED(len);

		n = readstr(offset, a, n, p);
		poperror();
		free(p);

		return n;

	case Qvgaovl:
	case Qvgaovlctl:
		error(Ebadusefd);
		break;

	default:
		error(Egreg);
		break;
	}

	return 0;
}
Exemple #25
0
int
screensize(int x, int y, int z, uint32_t chan)
{
	Proc *up = externup();
	VGAscr *scr;
	void *oldsoft;

	lock(&vgascreenlock);
	if(waserror()){
		unlock(&vgascreenlock);
		nexterror();
	}

	memimageinit();
	scr = &vgascreen[0];
	oldsoft = softscreen;

	if(scr->paddr == 0){
		int width = (x*z)/BI2WD;
		void *p;

		p = malloc(width*BY2WD*y);
		if(p == nil)
			error("no memory for vga soft screen");
		gscreendata.bdata = softscreen = p;
		if(scr->dev && scr->dev->page){
			scr->vaddr = KADDR(VGAMEM());
			scr->apsize = 1<<16;
		}
		scr->useflush = 1;
	}
	else{
		gscreendata.bdata = scr->vaddr;
		scr->useflush = scr->dev && scr->dev->flush;
	}

	scr->gscreen = nil;
	if(gscreen)
		freememimage(gscreen);
	gscreen = allocmemimaged(Rect(0,0,x,y), chan, &gscreendata);
	if(gscreen == nil)
		error("no memory for vga memimage");
	vgaimageinit(chan);

	scr->palettedepth = 6;	/* default */
	scr->gscreendata = &gscreendata;
	scr->memdefont = getmemdefont();
	scr->gscreen = gscreen;

	physgscreenr = gscreen->r;
	unlock(&vgascreenlock);
	poperror();
	if(oldsoft)
		free(oldsoft);

	memimagedraw(gscreen, gscreen->r, memblack, ZP, nil, ZP, S);
	flushmemscreen(gscreen->r);

	if(didswcursorinit)
		swcursorinit();
	drawcmap();
	return 0;
}
Exemple #26
0
static int32_t
consread(Chan *c, void *buf, int32_t n, int64_t off)
{
	Proc *up = externup();
	uint32_t l;
	Mach *mp;
	char *b, *bp, *s, *e;
	char tmp[512];		/* Qswap is 381 bytes at clu */
	int i, k, id;
	int32_t offset;


	if(n <= 0)
		return n;

	offset = off;
	switch((uint32_t)c->qid.path){
	case Qdir:
		return devdirread(c, buf, n, consdir, nelem(consdir), devgen);

	case Qcons:
		error(Egreg);

	case Qcputime:
		k = offset;
		if(k >= 6*NUMSIZE)
			return 0;
		if(k+n > 6*NUMSIZE)
			n = 6*NUMSIZE - k;
		/* easiest to format in a separate buffer and copy out */
		for(i=0; i<6 && NUMSIZE*i<k+n; i++){
			l = up->time[i];
			if(i == TReal)
				l = sys->ticks - l;
			l = TK2MS(l);
			readnum(0, tmp+NUMSIZE*i, NUMSIZE, l, NUMSIZE);
		}
		memmove(buf, tmp+k, n);
		return n;

	case Qkmesg:
		/*
		 * This is unlocked to avoid tying up a process
		 * that's writing to the buffer.  kmesg.n never
		 * gets smaller, so worst case the reader will
		 * see a slurred buffer.
		 */
		if(off >= kmesg.n)
			n = 0;
		else{
			if(off+n > kmesg.n)
				n = kmesg.n - off;
			memmove(buf, kmesg.buf+off, n);
		}
		return n;

	case Qkprint:
		error(Egreg);

	case Qpgrpid:
		return readnum(offset, buf, n, up->pgrp->pgrpid, NUMSIZE);

	case Qpid:
		return readnum(offset, buf, n, up->pid, NUMSIZE);

	case Qppid:
		return readnum(offset, buf, n, up->parentpid, NUMSIZE);

	case Qtime:
		return readtime(offset, buf, n);

	case Qbintime:
		return readbintime(buf, n);

	case Qhostowner:
		return readstr(offset, buf, n, eve);

	case Qhostdomain:
		return readstr(offset, buf, n, hostdomain);

	case Quser:
		return readstr(offset, buf, n, up->user);

	case Qnull:
		return 0;

	case Qsysstat:
		n = MACHMAX*(NUMSIZE*11+2+1);
		b = smalloc(n + 1);	/* +1 for NUL */
		bp = b;
		e = bp + n;
		for(id = 0; id < MACHMAX; id++)
			if((mp = sys->machptr[id]) != nil && mp->online){
				readnum(0, bp, NUMSIZE, mp->machno, NUMSIZE);
				bp += NUMSIZE;
				readnum(0, bp, NUMSIZE, mp->cs, NUMSIZE);
				bp += NUMSIZE;
				readnum(0, bp, NUMSIZE, mp->intr, NUMSIZE);
				bp += NUMSIZE;
				readnum(0, bp, NUMSIZE, mp->syscall, NUMSIZE);
				bp += NUMSIZE;
				readnum(0, bp, NUMSIZE, mp->pfault, NUMSIZE);
				bp += NUMSIZE;
				readnum(0, bp, NUMSIZE, mp->tlbfault, NUMSIZE);
				bp += NUMSIZE;
				readnum(0, bp, NUMSIZE, mp->tlbpurge, NUMSIZE);
				bp += NUMSIZE;
				readnum(0, bp, NUMSIZE, sys->load, NUMSIZE);
				bp += NUMSIZE;
				readnum(0, bp, NUMSIZE,
					(mp->perf.avg_inidle*100)/mp->perf.period,
					NUMSIZE);
				bp += NUMSIZE;
				readnum(0, bp, NUMSIZE,
					(mp->perf.avg_inintr*100)/mp->perf.period,
					NUMSIZE);
				bp += NUMSIZE;
				readnum(0, bp, NUMSIZE, 0, NUMSIZE); /* sched # */
				bp += NUMSIZE;
				bp = strecpy(bp, e, rolename[mp->nixtype]);
				*bp++ = '\n';
			}
		if(waserror()){
			free(b);
			nexterror();
		}
		n = readstr(offset, buf, n, b);
		free(b);
		poperror();
		return n;

	case Qswap:
		tmp[0] = 0;
		s = seprintpagestats(tmp, tmp + sizeof tmp);
		s = seprintphysstats(s, tmp + sizeof tmp);
		b = buf;
		l = s - tmp;
		i = readstr(offset, b, l, tmp);
		b += i;
		n -= i;
		if(offset > l)
			offset -= l;
		else
			offset = 0;

		return i + mallocreadsummary(c, b, n, offset);

	case Qsysname:
		if(sysname == nil)
			return 0;
		return readstr(offset, buf, n, sysname);

	case Qrandom:
		return randomread(buf, n);

	case Qurandom:
		return urandomread(buf, n);

	case Qdrivers:
		return devtabread(c, buf, n, off);

	case Qzero:
		memset(buf, 0, n);
		return n;

	case Qosversion:
		snprint(tmp, sizeof tmp, "2000");
		n = readstr(offset, buf, n, tmp);
		return n;

	case Qdebug:
		s = seprint(tmp, tmp + sizeof tmp, "locks %uld\n", lockstats.locks);
		s = seprint(s, tmp + sizeof tmp, "glare %uld\n", lockstats.glare);
		s = seprint(s, tmp + sizeof tmp, "inglare %uld\n", lockstats.inglare);
		s = seprint(s, tmp + sizeof tmp, "qlock %uld\n", qlockstats.qlock);
		seprint(s, tmp + sizeof tmp, "qlockq %uld\n", qlockstats.qlockq);
		return readstr(offset, buf, n, tmp);
		break;
	default:
		print("consread %#llux\n", c->qid.path);
		error(Egreg);
	}
	return -1;		/* never reached */
}
Exemple #27
0
char *
edfadmit(Proc *p)
{
	Proc *up = externup();
	char *err;
	Edf *e;
	int i;
	Proc *r;
	int32_t tns;

	e = p->edf;
	if (e->flags & Admitted)
		return "task state";	/* should never happen */

	/* simple sanity checks */
	if (e->T == 0)
		return "T not set";
	if (e->C == 0)
		return "C not set";
	if (e->D > e->T)
		return "D > T";
	if (e->D == 0)	/* if D is not set, set it to T */
		e->D = e->T;
	if (e->C > e->D)
		return "C > D";

	qlock(&edfschedlock);
	if (err = testschedulability(p)){
		qunlock(&edfschedlock);
		return err;
	}
	e->flags |= Admitted;

	edflock(p);

	if(p->trace)
		proctrace(p, SAdmit, 0);

	/* Look for another proc with the same period to synchronize to */
	for(i=0; (r = psincref(i)) != nil; i++) {
		if(r->state == Dead || r == p){
			psdecref(r);
			continue;
		}
		if (r->edf == nil || (r->edf->flags & Admitted) == 0){
			psdecref(r);
			continue;
		}
		if (r->edf->T == e->T)
			break;
	}
	if (r == nil){
		/* Can't synchronize to another proc, release now */
		e->t = now;
		e->d = 0;
		release(p);
		if (p == up){
			DPRINT("%lu edfadmit self %d[%s], release now: r=%lu d=%lu t=%lu\n",
				now, p->pid, statename[p->state], e->r, e->d, e->t);
			/* We're already running */
			edfrun(p, 1);
		}else{
			/* We're releasing another proc */
			DPRINT("%lu edfadmit other %d[%s], release now: r=%lu d=%lu t=%lu\n",
				now, p->pid, statename[p->state], e->r, e->d, e->t);
			p->Timer.ta = p;
			edfunlock();
			qunlock(&edfschedlock);
			releaseintr(nil, &p->Timer);
			return nil;
		}
	}else{
		/* Release in synch to something else */
		e->t = r->edf->t;
		psdecref(r);
		if (p == up){
			DPRINT("%lu edfadmit self %d[%s], release at %lu\n",
				now, p->pid, statename[p->state], e->t);
		}else{
			DPRINT("%lu edfadmit other %d[%s], release at %lu\n",
				now, p->pid, statename[p->state], e->t);
			if(e->Timer.tt == nil){
				e->Timer.tf = releaseintr;
				e->Timer.ta = p;
				tns = e->t - now;
				if(tns < 20)
					tns = 20;
				e->Timer.tns = 1000LL * tns;
				e->Timer.tmode = Trelative;
				timeradd(&e->Timer);
			}
		}
	}
	edfunlock();
	qunlock(&edfschedlock);
	return nil;
}
Exemple #28
0
static int32_t
conswrite(Chan *c, void *va, int32_t n, int64_t off)
{
	Proc *up = externup();
	char buf[256];
	int32_t l, bp;
	char *a;
	Mach *mp;
	int i;
	uint32_t offset;
	Cmdbuf *cb;
	Cmdtab *ct;
	a = va;
	offset = off;
	extern int printallsyscalls;

	switch((uint32_t)c->qid.path){
	case Qcons:
		/*
		 * Can't page fault in putstrn, so copy the data locally.
		 */
		l = n;
		while(l > 0){
			bp = l;
			if(bp > sizeof buf)
				bp = sizeof buf;
			memmove(buf, a, bp);
			putstrn0(buf, bp, 1);
			a += bp;
			l -= bp;
		}
		break;

	case Qconsctl:
		print("consctl\n");
		if(n >= sizeof(buf))
			n = sizeof(buf)-1;
		strncpy(buf, a, n);
		buf[n] = 0;
		for(a = buf; a;){
			if(strncmp(a, "sys", 3) == 0) {
				printallsyscalls = ! printallsyscalls;
				print("%sracing syscalls\n", printallsyscalls ? "T" : "Not t");
			}
			if(a = strchr(a, ' '))
				a++;
		}
		break;

	case Qtime:
		if(!iseve())
			error(Eperm);
		return writetime(a, n);

	case Qbintime:
		if(!iseve())
			error(Eperm);
		return writebintime(a, n);

	case Qhostowner:
		return hostownerwrite(a, n);

	case Qhostdomain:
		return hostdomainwrite(a, n);

	case Quser:
		return userwrite(a, n);

	case Qnull:
		break;

	case Qreboot:
		if(!iseve())
			error(Eperm);
		cb = parsecmd(a, n);

		if(waserror()) {
			free(cb);
			nexterror();
		}
		ct = lookupcmd(cb, rebootmsg, nelem(rebootmsg));
		switch(ct->index) {
		case CMhalt:
			reboot(nil, 0, 0);
			break;
		case CMreboot:
			rebootcmd(cb->nf-1, cb->f+1);
			break;
		case CMpanic:
			*(uint32_t*)0=0;
			panic("/dev/reboot");
		}
		poperror();
		free(cb);
		break;

	case Qsysstat:
		for(i = 0; i < MACHMAX; i++)
			if((mp = sys->machptr[i]) != nil && mp->online){
				mp = sys->machptr[i];
				mp->cs = 0;
				mp->intr = 0;
				mp->syscall = 0;
				mp->pfault = 0;
				mp->tlbfault = 0;	/* not updated */
				mp->tlbpurge = 0;	/* # mmuflushtlb */
			}
		break;

	case Qswap:
		if(n >= sizeof buf)
			error(Egreg);
		memmove(buf, va, n);	/* so we can NUL-terminate */
		buf[n] = 0;
		if(!iseve())
			error(Eperm);
		if(buf[0]<'0' || '9'<buf[0])
			error(Ebadarg);
		if(strncmp(buf, "start", 5) == 0){
			print("request to start pager ignored\n");
			break;
		}
		break;

	case Qsysname:
		if(offset != 0)
			error(Ebadarg);
		if(n <= 0 || n >= sizeof buf)
			error(Ebadarg);
		strncpy(buf, a, n);
		buf[n] = 0;
		if(buf[n-1] == '\n')
			buf[n-1] = 0;
		kstrdup(&sysname, buf);
		break;

	case Qdebug:
		if(n >= sizeof(buf))
			n = sizeof(buf)-1;
		strncpy(buf, a, n);
		buf[n] = 0;
		if(n > 0 && buf[n-1] == '\n')
			buf[n-1] = 0;
		error(Ebadctl);
		break;
	default:
		print("conswrite: %#llux\n", c->qid.path);
		error(Egreg);
	}
	return n;
}
Exemple #29
0
/* if dc is non-zero, it means we're doing a mount and dc is the mount device to use. */
static int
bindmount(int dc, int fd, int afd, char* arg0, char* arg1, int flag, char* spec)
{
	Proc *up = externup();
	int i;
	Dev *dev;
	Chan *c0, *c1, *ac, *bc;
	struct{
		Chan	*chan;
		Chan	*authchan;
		char	*spec;
		int	flags;
	}bogus;

	if((flag&~MMASK) || (flag&MORDER)==(MBEFORE|MAFTER))
		error(Ebadarg);

	bogus.flags = flag & MCACHE;

	if(dc){
		if (! checkdc(dc))
			error(Ebadarg);

		if(up->pgrp->noattach)
			error(Enoattach);

		ac = nil;
		bc = fdtochan(fd, ORDWR, 0, 1);
		if(waserror()) {
			if(ac)
				cclose(ac);
			cclose(bc);
			nexterror();
		}

		if(afd >= 0)
			ac = fdtochan(afd, ORDWR, 0, 1);

		bogus.chan = bc;
		bogus.authchan = ac;

		bogus.spec = validaddr(spec, 1, 0);
		if(waserror())
			error(Ebadspec);
		spec = validnamedup(spec, 1);
		poperror();

		if(waserror()){
			free(spec);
			nexterror();
		}

		dev = devtabget(dc, 0);		//XDYNX
		if(waserror()){
			//devtabdecr(dev);
			nexterror();
		}
		c0 = dev->attach((char*)&bogus);
		poperror();
		//devtabdecr(dev);

		poperror();	/* spec */
		free(spec);
		poperror();	/* ac bc */
		if(ac)
			cclose(ac);
		cclose(bc);
	}else{
		bogus.spec = nil;
		c0 = namec(validaddr(arg0, 1, 0), Abind, 0, 0);
	}

	if(waserror()){
		cclose(c0);
		nexterror();
	}

	c1 = namec(validaddr(arg1, 1, 0), Amount, 0, 0);
	if(waserror()){
		cclose(c1);
		nexterror();
	}

	i = cmount(&c0, c1, flag, bogus.spec);

	poperror();
	cclose(c1);
	poperror();
	cclose(c0);
	if(dc)
		fdclose(fd, 0);

	return i;
}
Exemple #30
0
static int
tfn(void *arg)
{
	Proc *up = externup();
	return up->trend == nil || up->tfn(arg);
}