Пример #1
0
/*
 * can be called with up == nil during boot.
 */
Page*
newpage(int clear, Segment **s, uintptr_t va, usize size, int color)
{
	Page *p;
	KMap *k;
	uint8_t ct;
	Pgsza *pa;
	int i, dontalloc, si;
	//	static int once;

	si = getpgszi(size);
//iprint("(remove this print and diea)newpage, size %x, si %d\n", size, si);
	pa = &pga.pgsza[si];

	lock(&pga.l);
	/*
	 * Beware, new page may enter a loop even if this loop does not
	 * loop more than once, if the segment is lost and fault calls us
	 * again. Either way, we accept any color if we failed a couple of times.
	 */
	for(i = 0;; i++){
		if(i > 3)
			color = NOCOLOR;

		/*
		 * 1. try to reuse a free one.
		 */
		p = findpg(pa->head, color);
		if(p != nil)
			break;

		/*
		 * 2. try to allocate a new one from physical memory
		 */
		p = pgalloc(size, color);
		if(p != nil){
			pagechainhead(p);
			break;
		}

		/*
		 * 3. out of memory, try with the pager.
		 * but release the segment (if any) while in the pager.
		 */
		unlock(&pga.l);

		dontalloc = 0;
		if(s && *s) {
			qunlock(&((*s)->lk));
			*s = 0;
			dontalloc = 1;
		}

		/*
		 * Try to get any page of the desired color
		 * or any color for NOCOLOR.
		 */
		kickpager(si, color);

		/*
		 * If called from fault and we lost the segment from
		 * underneath don't waste time allocating and freeing
		 * a page. Fault will call newpage again when it has
		 * reacquired the segment locks
		 */
		if(dontalloc)
			return 0;

		lock(&pga.l);
	}

	assert(p != nil);
	ct = PG_NEWCOL;

	pageunchain(p);

	lock(&p->l);
	if(p->ref != 0)
		panic("newpage pa %#ullx", p->pa);

	uncachepage(p);
	p->ref++;
	p->va = va;
	p->modref = 0;
	for(i = 0; i < nelem(p->cachectl); i++)
		p->cachectl[i] = ct;
	unlock(&p->l);
	unlock(&pga.l);

	if(clear) {
		k = kmap(p);
if (VA(k) == 0xfffffe007d800000ULL) trip++;
//	if (trip) die("trip before memset");
		// This will frequently die if we use 3K-1 (3071 -- 0xbff)
		// it will not if we use 3070.
		// The fault is a null pointer deref.
		//memset((void*)VA(k), 0, machp()->pgsz[p->pgszi]);
		// thinking about it, using memset is stupid.
		// Don't get upset about this loop;
		// we make it readable, compilers optimize it.
		int i;
		uint64_t *v = (void *)VA(k);
		if (1)
		for(i = 0; i < sys->pgsz[p->pgszi]/sizeof(*v); i++)
			v[i] = 0;
//if (trip) die("trip");
		kunmap(k);
	}
	DBG("newpage: va %#p pa %#ullx pgsz %#ux color %d\n",
		p->va, p->pa, sys->pgsz[p->pgszi], p->color);

	return p;
}
Пример #2
0
Page*
newpage(int clear, Segment **s, ulong va)
{
	Page *p;
	KMap *k;
	uchar ct;
	int i, hw, dontalloc, color;

	lock(&palloc);
	color = getpgcolor(va);
	hw = swapalloc.highwater;
	for(;;) {
		if(palloc.freecount > hw)
			break;
		if(up->kp && palloc.freecount > 0)
			break;

		unlock(&palloc);
		dontalloc = 0;
		if(s && *s) {
			qunlock(&((*s)->lk));
			*s = 0;
			dontalloc = 1;
		}
		qlock(&palloc.pwait);	/* Hold memory requesters here */

		while(waserror())	/* Ignore interrupts */
			;

		kickpager();
		tsleep(&palloc.r, ispages, 0, 1000);

		poperror();

		qunlock(&palloc.pwait);

		/*
		 * If called from fault and we lost the segment from
		 * underneath don't waste time allocating and freeing
		 * a page. Fault will call newpage again when it has
		 * reacquired the segment locks
		 */
		if(dontalloc)
			return 0;

		lock(&palloc);
	}

	/* First try for our colour */
	for(p = palloc.head; p; p = p->next)
		if(p->color == color)
			break;

	ct = PG_NOFLUSH;
	if(p == 0) {
		p = palloc.head;
		p->color = color;
		ct = PG_NEWCOL;
	}

	pageunchain(p);

	lock(p);
	if(p->ref != 0)
		panic("newpage: p->ref %d != 0", p->ref);

	uncachepage(p);
	p->ref++;
	p->va = va;
	p->modref = 0;
	for(i = 0; i < MAXMACH; i++)
		p->cachectl[i] = ct;
	unlock(p);
	unlock(&palloc);

	if(clear) {
		k = kmap(p);
		memset((void*)VA(k), 0, BY2PG);
		kunmap(k);
	}

	return p;
}
Пример #3
0
static long
conswrite(Chan *c, void *va, long n, vlong off)
{
	char buf[256];
	long l, bp;
	char *a;
	Mach *mp;
	int id, fd;
	Chan *swc;
	ulong offset;
	Cmdbuf *cb;
	Cmdtab *ct;

	a = va;
	offset = off;

	switch((ulong)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:
		error(Egreg);

	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 Qconfig:
		error(Eperm);
		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:
			*(ulong*)0=0;
			panic("/dev/reboot");
		case CMrdb:
			if(consdebug == nil)
				consdebug = rdb;
			consdebug();
			break;
		}
		poperror();
		free(cb);
		break;

	case Qsysstat:
		for(id = 0; id < 32; id++) {
			if(active.machs & (1<<id)) {
				mp = MACHP(id);
				mp->cs = 0;
				mp->intr = 0;
				mp->syscall = 0;
				mp->pfault = 0;
				mp->tlbfault = 0;
				mp->tlbpurge = 0;
			}
		}
		break;

	case Qswap:
		if(n >= sizeof buf)
			error(Egreg);
		memmove(buf, va, n);	/* so we can NUL-terminate */
		buf[n] = 0;
		/* start a pager if not already started */
		if(strncmp(buf, "start", 5) == 0){
			kickpager();
			break;
		}
		if(!iseve())
			error(Eperm);
		if(buf[0]<'0' || '9'<buf[0])
			error(Ebadarg);
		fd = strtoul(buf, 0, 0);
		swc = fdtochan(fd, -1, 1, 1);
		setswapchan(swc);
		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 Qmordor:
		error("one does not simply write into mordor");
		return 0;

	default:
		print("conswrite: %#llux\n", c->qid.path);
		error(Egreg);
	}
	return n;
}
Пример #4
0
static long conswrite(struct chan *c, void *va, long n, int64_t off)
{
    ERRSTACK(1);
    char buf[256], ch;
    long l, bp;
    char *a;
    //Mach *mp;
    int id, fd;
    struct chan *swc;
    uint32_t offset;
    struct cmdbuf *cb;
    struct cmdtab *ct;
    int x;
    uint64_t rip, rsp, cr3, flags, vcpu;
    int ret;
    struct vmctl vmctl;

    a = va;
    offset = off;

    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:
        if (n >= sizeof(buf))
            n = sizeof(buf) - 1;
        strncpy(buf, a, n);
        buf[n] = 0;
        for (a = buf; a;) {
            if (strncmp(a, "rawon", 5) == 0) {
                kbd.raw = 1;
                /* clumsy hack - wake up reader */
                ch = 0;
                qwrite(kbdq, &ch, 1);
            } else if (strncmp(a, "rawoff", 6) == 0) {
                kbd.raw = 0;
            } else if (strncmp(a, "ctlpon", 6) == 0) {
                kbd.ctlpoff = 0;
            } else if (strncmp(a, "ctlpoff", 7) == 0) {
                kbd.ctlpoff = 1;
            }
            if ((a = strchr(a, ' ')) != NULL)
                a++;
        }
        break;

    case Qtime:
        if (!iseve())
            error(EPERM, "Hodie Natus Est Radici Frater");
        return writetime(a, n);

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

#if 0
    case Qhostowner:
        return hostownerwrite(a, n);

    case Qhostdomain:
        return hostdomainwrite(a, n);

    case Quser:
        return userwrite(a, n);
#endif

    case Qnull:
        break;

    case Qconfig:
        error(EPERM, "Cannot write to config QID");
        break;

    case Qsysctl:
        //if (!iseve()) error(EPERM, ERROR_FIXME);
        cb = parsecmd(a, n);
        if (cb->nf > 1)
            printd("cons sysctl cmd %s\n", cb->f[0]);

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

        if (waserror()) {
            kfree(cb);
            nexterror();
        }
        ct = lookupcmd(cb, rebootmsg, ARRAY_SIZE(rebootmsg));
        switch (ct->index) {
        case CMhalt:
            cpu_halt();
            break;
        case CMbroken:
            keepbroken = 1;
            break;
        case CMnobroken:
            keepbroken = 0;
            break;
        case CMreboot:
            reboot();
            break;
        case CMpanic:
            *(uint32_t *) 0 = 0;
            panic("/dev/reboot");
        }
        poperror();
        kfree(cb);
        break;

#if 0
    case Qsysstat:
        for (id = 0; id < 32; id++) {
            if (active.machs & (1 << id)) {
                mp = MACHP(id);
                mp->cs = 0;
                mp->intr = 0;
                mp->syscall = 0;
                mp->pfault = 0;
                mp->tlbfault = 0;
                mp->tlbpurge = 0;
            }
        }
        break;

    case Qswap:
        if (n >= sizeof buf)
            error(EINVAL, "n is bigger than sizeof buf for Qswap");
        memmove(buf, va, n);	/* so we can NUL-terminate */
        buf[n] = 0;
        /* start a pager if not already started */
        if (strncmp(buf, "start", 5) == 0) {
            kickpager();
            break;
        }
        if (!iseve())
            error(EPERM, ERROR_FIXME);
        if (buf[0] < '0' || '9' < buf[0])
            error(EINVAL, ERROR_FIXME);
        fd = strtoul(buf, 0, 0);
        swc = fdtochan(fd, -1, 1, 1);
        setswapchan(swc);
        break;
#endif

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

    default:
        printd("conswrite: %#llux\n", c->qid.path);
        error(EINVAL, "bad QID in conswrite");
    }
    return n;
}