/* * 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; }
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; }
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; }
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; }