#include "u.h"#include "../port/lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "../port/error.h" #include <authsrv.h> enum{ Nconsdevs = 64, /* max number of consoles */ /* Consdev flags */ Ciprint = 2, /* call this fn from iprint */ Cntorn = 4, /* change \n to \r\n */}; typedef struct Consdev Consdev; struct Consdev{ Chan* c; /* external file */ Queue* q; /* i/o queue, if any */ void (*fn)(char*, int); /* i/o function when no queue */ int flags;}; void (*consdebug)(void) = nil;void (*consputs)(char*, int) = nil; static void kmesgputs(char *, int);static void kprintputs(char*, int); static Lock consdevslock;static int nconsdevs = 3;static Consdev consdevs[Nconsdevs] = /* keep this order */{ {nil, nil, kmesgputs, 0}, /* kmesg */ {nil, nil, kprintputs, Ciprint}, /* kprint */ {nil, nil, uartputs, Ciprint|Cntorn}, /* serial */}; static int nkbdqs;static int nkbdprocs;static Queue* kbdqs[Nconsdevs];static int kbdprocs[Nconsdevs];static Queue* kbdq; /* unprocessed console input */static Queue* lineq; /* processed console input */static Queue* serialoq; /* serial console output */static Queue* kprintoq; /* console output, for /dev/kprint */static ulong kprintinuse; /* test and set whether /dev/kprint is open */ int panicking; static struct{ QLock; int raw; /* true if we shouldn't process input */ Ref ctl; /* number of opens to the control file */ int x; /* index into line */ char line[1024]; /* current input line */ int count; int ctlpoff; /* * A place to save up characters at interrupt time * before dumping them in the queue */ Lock lockputc; char istage[1024]; char *iw; char *ir; char *ie;} kbd = { .iw = kbd.istage, .ir = kbd.istage, .ie = kbd.istage + sizeof(kbd.istage),}; char *sysname;vlong fasthz; static void seedrand(void);static int readtime(ulong, char*, int);static int readbintime(char*, int);static int writetime(char*, int);static int writebintime(char*, int); enum{ CMhalt, CMreboot, CMpanic,}; Cmdtab rebootmsg[] ={ CMhalt, "halt", 1, CMreboot, "reboot", 0, CMpanic, "panic", 0,}; /* To keep the rest of the kernel unware of new consdevs for now */static voidkprintputs(char *s, int n){ if(consputs != nil) consputs(s, n);} intaddconsdev(Queue *q, void (*fn)(char*,int), int i, int flags){ Consdev *c; ilock(&consdevslock); if(i < 0) i = nconsdevs; else flags |= consdevs[i].flags; if(nconsdevs == Nconsdevs) panic("Nconsdevs too small"); c = &consdevs[i]; c->flags = flags; c->q = q; c->fn = fn; if(i == nconsdevs) nconsdevs++; iunlock(&consdevslock); return i;} voiddelconsdevs(void){ nconsdevs = 2; /* throw away serial consoles and kprint */ consdevs[1].q = nil;} static voidconskbdqproc(void *a){ char buf[64]; Queue *q; int nr; q = a; while((nr = qread(q, buf, sizeof(buf))) > 0) qwrite(kbdq, buf, nr); pexit("hangup", 1);} static voidkickkbdq(void){ int i; if(up != nil && nkbdqs > 1 && nkbdprocs != nkbdqs){ lock(&consdevslock); if(nkbdprocs == nkbdqs){ unlock(&consdevslock); return; } for(i = 0; i < nkbdqs; i++) if(kbdprocs[i] == 0){ kbdprocs[i] = 1; kproc("conskbdq", conskbdqproc, kbdqs[i]); } unlock(&consdevslock); }} intaddkbdq(Queue *q, int i){ int n; ilock(&consdevslock); if(i < 0) i = nkbdqs++; if(nkbdqs == Nconsdevs) panic("Nconsdevs too small"); kbdqs[i] = q; n = nkbdqs; iunlock(&consdevslock); switch(n){ case 1: /* if there's just one, pull directly from it. */ kbdq = q; break; case 2: /* later we'll merge bytes from all kbdqs into a single kbdq */ kbdq = qopen(4*1024, 0, 0, 0); if(kbdq == nil) panic("no kbdq"); /* fall */ default: kickkbdq(); } return i;} voidprintinit(void){ lineq = qopen(2*1024, 0, nil, nil); if(lineq == nil) panic("printinit"); qnoblock(lineq, 1);} intconsactive(void){ int i; Queue *q; for(i = 0; i < nconsdevs; i++) if((q = consdevs[i].q) != nil && qlen(q) > 0) return 1; return 0;} voidprflush(void){ ulong now; now = m->ticks; while(consactive()) if(m->ticks - now >= HZ) break;} /* * Log console output so it can be retrieved via /dev/kmesg. * This is good for catching boot-time messages after the fact. */struct { Lock lk; char buf[16384]; uint n;} kmesg; static voidkmesgputs(char *str, int n){ uint nn, d; ilock(&kmesg.lk); /* take the tail of huge writes */ if(n > sizeof kmesg.buf){ d = n - sizeof kmesg.buf; str += d; n -= d; } /* slide the buffer down to make room */ nn = kmesg.n; if(nn + n >= sizeof kmesg.buf){ d = nn + n - sizeof kmesg.buf; if(d) memmove(kmesg.buf, kmesg.buf+d, sizeof kmesg.buf-d); nn -= d; } /* copy the data in */ memmove(kmesg.buf+nn, str, n); nn += n; kmesg.n = nn; iunlock(&kmesg.lk);} static voidconsdevputs(Consdev *c, char *s, int n, int usewrite){ Chan *cc; Queue *q; if((cc = c->c) != nil && usewrite) cc->dev->write(cc, s, n, 0); else if((q = c->q) != nil && !qisclosed(q)) if(usewrite) qwrite(q, s, n); else qiwrite(q, s, n); else if(c->fn != nil) c->fn(s, n);} /* * Print a string on the console. Convert \n to \r\n for serial * line consoles. Locking of the queues is left up to the screen * or uart code. Multi-line messages to serial consoles may get * interspersed with other messages. */static voidputstrn0(char *str, int n, int usewrite){ Consdev *c; char *s, *t; int i, len, m; if(!islo()) usewrite = 0; for(i = 0; i < nconsdevs; i++){ c = &consdevs[i]; len = n; s = str; while(len > 0){ t = nil; if((c->flags&Cntorn) && !kbd.raw) t = memchr(s, '\n', len); if(t != nil && !kbd.raw){ m = t-s; consdevputs(c, s, m, usewrite); consdevputs(c, "\r\n", 2, usewrite); len -= m+1; s = t+1; }else{ consdevputs(c, s, len, usewrite); break; } } }} voidputstrn(char *str, int n){ putstrn0(str, n, 0);} intprint(char *fmt, ...){ int n; va_list arg; char buf[PRINTSIZE]; va_start(arg, fmt); n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf; va_end(arg); putstrn(buf, n); return n;} /* * Want to interlock iprints to avoid interlaced output on * multiprocessor, but don't want to deadlock if one processor * dies during print and another has something important to say. * Make a good faith effort. */static Lock iprintlock; static intiprintcanlock(Lock *l){ int i; for(i=0; i<1000; i++){ if(canlock(l)) return 1; if(l->m == MACHP(m->machno)) return 0; microdelay(100); } return 0;} intiprint(char *fmt, ...){ Mreg s; int i, n, locked; va_list arg; char buf[PRINTSIZE]; s = splhi(); va_start(arg, fmt); n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf; va_end(arg); locked = iprintcanlock(&iprintlock); for(i = 0; i < nconsdevs; i++) if((consdevs[i].flags&Ciprint) != 0) consdevs[i].fn(buf, n); if(locked) unlock(&iprintlock); splx(s); return n;} #pragma profile 0voidpanic(char *fmt, ...){ int n; Mreg s; va_list arg; char buf[PRINTSIZE]; consdevs[1].q = nil; /* don't try to write to /dev/kprint */ if(panicking) for(;;); panicking = 1; s = splhi(); strcpy(buf, "panic: "); va_start(arg, fmt); n = vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg) - buf; va_end(arg); iprint("%s\n", buf); if(consdebug) (*consdebug)(); splx(s); prflush(); buf[n] = '\n'; putstrn(buf, n+1); dumpstack(); exit(1);}#pragma profile 1/* libmp at least contains a few calls to sysfatal; simulate with panic */voidsysfatal(char *fmt, ...){ char err[256]; va_list arg; va_start(arg, fmt); vseprint(err, err + sizeof err, fmt, arg); va_end(arg); panic("sysfatal: %s", err);} void_assert(char *fmt){ panic("assert failed at %#p: %s", getcallerpc(&fmt), fmt);} intpprint(char *fmt, ...){ int n; Chan *c; va_list arg; char buf[2*PRINTSIZE]; if(up == nil || up->fgrp == nil) return 0; c = up->fgrp->fd[2]; if(c==0 || (c->mode!=OWRITE && c->mode!=ORDWR)) return 0; n = snprint(buf, sizeof buf, "%s %d: ", up->text, up->pid); va_start(arg, fmt); n = vseprint(buf+n, buf+sizeof(buf), fmt, arg) - buf; va_end(arg); if(waserror()) return 0; c->dev->write(c, buf, n, c->offset); poperror(); lock(c); c->offset += n; unlock(c); return n;} static voidecho(char *buf, int n){ Mreg s; static int ctrlt, pid; char *e, *p; if(n == 0) return; e = buf+n; for(p = buf; p < e; p++){ switch(*p){ case 0x10: /* ^P */ if(cpuserver && !kbd.ctlpoff){ active.exiting = 1; return; } break; case 0x14: /* ^T */Lines 1–500 of 1403. Load more
#include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "../port/error.h" #include <authsrv.h> enum { Nconsdevs = 64, /* max number of consoles */ /* Consdev flags */ Ciprint = 2, /* call this fn from iprint */ Cntorn = 4, /* change \n to \r\n */ }; typedef struct Consdev Consdev; struct Consdev { Chan* c; /* external file */ Queue* q; /* i/o queue, if any */ void (*fn)(char*, int); /* i/o function when no queue */ int flags; }; void (*consdebug)(void) = nil; void (*consputs)(char*, int) = nil; static void kmesgputs(char *, int); static void kprintputs(char*, int); static Lock consdevslock; static int nconsdevs = 3; static Consdev consdevs[Nconsdevs] = /* keep this order */ { {nil, nil, kmesgputs, 0}, /* kmesg */ {nil, nil, kprintputs, Ciprint}, /* kprint */ {nil, nil, uartputs, Ciprint|Cntorn}, /* serial */ }; static int nkbdqs; static int nkbdprocs; static Queue* kbdqs[Nconsdevs]; static int kbdprocs[Nconsdevs]; static Queue* kbdq; /* unprocessed console input */ static Queue* lineq; /* processed console input */ static Queue* serialoq; /* serial console output */ static Queue* kprintoq; /* console output, for /dev/kprint */ static ulong kprintinuse; /* test and set whether /dev/kprint is open */ int panicking; static struct { QLock; int raw; /* true if we shouldn't process input */ Ref ctl; /* number of opens to the control file */ int x; /* index into line */ char line[1024]; /* current input line */ int count; int ctlpoff; /* * A place to save up characters at interrupt time * before dumping them in the queue */ Lock lockputc; char istage[1024]; char *iw; char *ir; char *ie; } kbd = { .iw = kbd.istage, .ir = kbd.istage, .ie = kbd.istage + sizeof(kbd.istage), }; char *sysname; vlong fasthz; static void seedrand(void); static int readtime(ulong, char*, int); static int readbintime(char*, int); static int writetime(char*, int); static int writebintime(char*, int); enum { CMhalt, CMreboot, CMpanic, }; Cmdtab rebootmsg[] = { CMhalt, "halt", 1, CMreboot, "reboot", 0, CMpanic, "panic", 0, }; /* To keep the rest of the kernel unware of new consdevs for now */ static void kprintputs(char *s, int n) { if(consputs != nil) consputs(s, n); } int addconsdev(Queue *q, void (*fn)(char*,int), int i, int flags) { Consdev *c; ilock(&consdevslock); if(i < 0) i = nconsdevs; else flags |= consdevs[i].flags; if(nconsdevs == Nconsdevs) panic("Nconsdevs too small"); c = &consdevs[i]; c->flags = flags; c->q = q; c->fn = fn; if(i == nconsdevs) nconsdevs++; iunlock(&consdevslock); return i; } void delconsdevs(void) { nconsdevs = 2; /* throw away serial consoles and kprint */ consdevs[1].q = nil; } static void conskbdqproc(void *a) { char buf[64]; Queue *q; int nr; q = a; while((nr = qread(q, buf, sizeof(buf))) > 0) qwrite(kbdq, buf, nr); pexit("hangup", 1); } static void kickkbdq(void) { int i; if(up != nil && nkbdqs > 1 && nkbdprocs != nkbdqs){ lock(&consdevslock); if(nkbdprocs == nkbdqs){ unlock(&consdevslock); return; } for(i = 0; i < nkbdqs; i++) if(kbdprocs[i] == 0){ kbdprocs[i] = 1; kproc("conskbdq", conskbdqproc, kbdqs[i]); } unlock(&consdevslock); } } int addkbdq(Queue *q, int i) { int n; ilock(&consdevslock); if(i < 0) i = nkbdqs++; if(nkbdqs == Nconsdevs) panic("Nconsdevs too small"); kbdqs[i] = q; n = nkbdqs; iunlock(&consdevslock); switch(n){ case 1: /* if there's just one, pull directly from it. */ kbdq = q; break; case 2: /* later we'll merge bytes from all kbdqs into a single kbdq */ kbdq = qopen(4*1024, 0, 0, 0); if(kbdq == nil) panic("no kbdq"); /* fall */ default: kickkbdq(); } return i; } void printinit(void) { lineq = qopen(2*1024, 0, nil, nil); if(lineq == nil) panic("printinit"); qnoblock(lineq, 1); } int consactive(void) { int i; Queue *q; for(i = 0; i < nconsdevs; i++) if((q = consdevs[i].q) != nil && qlen(q) > 0) return 1; return 0; } void prflush(void) { ulong now; now = m->ticks; while(consactive()) if(m->ticks - now >= HZ) break; } /* * Log console output so it can be retrieved via /dev/kmesg. * This is good for catching boot-time messages after the fact. */ struct { Lock lk; char buf[16384]; uint n; } kmesg; static void kmesgputs(char *str, int n) { uint nn, d; ilock(&kmesg.lk); /* take the tail of huge writes */ if(n > sizeof kmesg.buf){ d = n - sizeof kmesg.buf; str += d; n -= d; } /* slide the buffer down to make room */ nn = kmesg.n; if(nn + n >= sizeof kmesg.buf){ d = nn + n - sizeof kmesg.buf; if(d) memmove(kmesg.buf, kmesg.buf+d, sizeof kmesg.buf-d); nn -= d; } /* copy the data in */ memmove(kmesg.buf+nn, str, n); nn += n; kmesg.n = nn; iunlock(&kmesg.lk); } static void consdevputs(Consdev *c, char *s, int n, int usewrite) { Chan *cc; Queue *q; if((cc = c->c) != nil && usewrite) cc->dev->write(cc, s, n, 0); else if((q = c->q) != nil && !qisclosed(q)) if(usewrite) qwrite(q, s, n); else qiwrite(q, s, n); else if(c->fn != nil) c->fn(s, n); } /* * Print a string on the console. Convert \n to \r\n for serial * line consoles. Locking of the queues is left up to the screen * or uart code. Multi-line messages to serial consoles may get * interspersed with other messages. */ static void putstrn0(char *str, int n, int usewrite) { Consdev *c; char *s, *t; int i, len, m; if(!islo()) usewrite = 0; for(i = 0; i < nconsdevs; i++){ c = &consdevs[i]; len = n; s = str; while(len > 0){ t = nil; if((c->flags&Cntorn) && !kbd.raw) t = memchr(s, '\n', len); if(t != nil && !kbd.raw){ m = t-s; consdevputs(c, s, m, usewrite); consdevputs(c, "\r\n", 2, usewrite); len -= m+1; s = t+1; }else{ consdevputs(c, s, len, usewrite); break; } } } } void putstrn(char *str, int n) { putstrn0(str, n, 0); } int print(char *fmt, ...) { int n; va_list arg; char buf[PRINTSIZE]; va_start(arg, fmt); n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf; va_end(arg); putstrn(buf, n); return n; } /* * Want to interlock iprints to avoid interlaced output on * multiprocessor, but don't want to deadlock if one processor * dies during print and another has something important to say. * Make a good faith effort. */ static Lock iprintlock; static int iprintcanlock(Lock *l) { int i; for(i=0; i<1000; i++){ if(canlock(l)) return 1; if(l->m == MACHP(m->machno)) return 0; microdelay(100); } return 0; } int iprint(char *fmt, ...) { Mreg s; int i, n, locked; va_list arg; char buf[PRINTSIZE]; s = splhi(); va_start(arg, fmt); n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf; va_end(arg); locked = iprintcanlock(&iprintlock); for(i = 0; i < nconsdevs; i++) if((consdevs[i].flags&Ciprint) != 0) consdevs[i].fn(buf, n); if(locked) unlock(&iprintlock); splx(s); return n; } #pragma profile 0 void panic(char *fmt, ...) { int n; Mreg s; va_list arg; char buf[PRINTSIZE]; consdevs[1].q = nil; /* don't try to write to /dev/kprint */ if(panicking) for(;;); panicking = 1; s = splhi(); strcpy(buf, "panic: "); va_start(arg, fmt); n = vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg) - buf; va_end(arg); iprint("%s\n", buf); if(consdebug) (*consdebug)(); splx(s); prflush(); buf[n] = '\n'; putstrn(buf, n+1); dumpstack(); exit(1); } #pragma profile 1 /* libmp at least contains a few calls to sysfatal; simulate with panic */ void sysfatal(char *fmt, ...) { char err[256]; va_list arg; va_start(arg, fmt); vseprint(err, err + sizeof err, fmt, arg); va_end(arg); panic("sysfatal: %s", err); } void _assert(char *fmt) { panic("assert failed at %#p: %s", getcallerpc(&fmt), fmt); } int pprint(char *fmt, ...) { int n; Chan *c; va_list arg; char buf[2*PRINTSIZE]; if(up == nil || up->fgrp == nil) return 0; c = up->fgrp->fd[2]; if(c==0 || (c->mode!=OWRITE && c->mode!=ORDWR)) return 0; n = snprint(buf, sizeof buf, "%s %d: ", up->text, up->pid); va_start(arg, fmt); n = vseprint(buf+n, buf+sizeof(buf), fmt, arg) - buf; va_end(arg); if(waserror()) return 0; c->dev->write(c, buf, n, c->offset); poperror(); lock(c); c->offset += n; unlock(c); return n; } static void echo(char *buf, int n) { Mreg s; static int ctrlt, pid; char *e, *p; if(n == 0) return; e = buf+n; for(p = buf; p < e; p++){ switch(*p){ case 0x10: /* ^P */ if(cpuserver && !kbd.ctlpoff){ active.exiting = 1; return; } break; case 0x14: /* ^T */