M gnot/dat.h => gnot/dat.h +0 -34
@@ 1,8 1,6 @@
typedef struct Conf Conf;
typedef struct FFrame FFrame;
typedef struct FPsave FPsave;
-typedef struct IOQ IOQ;
-typedef struct KIOQ KIOQ;
typedef struct KMap KMap;
typedef struct Label Label;
typedef struct Lock Lock;
@@ 120,38 118,6 @@ struct KMap
};
#define VA(k) ((k)->va)
-/*
- * character based IO (mouse, keyboard, console screen)
- */
-#define NQ 4096
-struct IOQ
-{
- Lock;
- uchar buf[NQ];
- uchar *in;
- uchar *out;
- int state;
- Rendez r;
- union{
- void (*puts)(IOQ*, void*, int); /* output */
- int (*putc)(IOQ*, int); /* input */
- };
- void *ptr;
-};
-struct KIOQ
-{
- QLock;
- IOQ;
- int repeat;
- int c;
- int count;
-};
-
-extern IOQ lineq;
-extern IOQ printq;
-extern IOQ mouseq;
-extern KIOQ kbdq;
-
struct Mach
{
int machno; /* physical id of processor */
M gnot/fns.h => gnot/fns.h +0 -23
@@ 57,26 57,3 @@ int splduart(void);
int tas(char*);
void touser(void);
#define waserror() (u->nerrlab++, setlabel(&u->errlab[u->nerrlab-1]))
-
-/*
- * for queues (to go into portfns.h)
- */
-int cangetc(void*);
-int canputc(void*);
-int getc(IOQ*);
-int gets(IOQ*, void*, int);
-void initq(IOQ*);
-int putc(IOQ*, int);
-void puts(IOQ*, void*, int);
-
-/*
- * for devcons (to go into portfns.h)
- */
-void kbdclock(void);
-void kbdrepeat(int);
-int kbdputc(IOQ*, int);
-int kprint(char*, ...);
-int mouseputc(IOQ*, int);
-void printinit(void);
-void putstr(char*);
-void putstrn(char*, long);
M port/devcons.c => port/devcons.c +269 -310
@@ 8,90 8,35 @@
#include "devtab.h"
-static struct
-{
- Lock;
- uchar buf[4000];
- uchar *in;
- uchar *out;
- int printing;
- int c;
-}printq;
-
-typedef struct IOQ IOQ;
-
-#define NQ 4096
-struct IOQ{
- union{
- Lock;
- QLock;
- };
- uchar buf[NQ];
- uchar *in;
- uchar *out;
- int state;
- Rendez r;
-};
-
-IOQ kbdq; /* qlock to getc; interrupt putc's */
-IOQ lineq; /* lock to getc; interrupt putc's */
-
-#define SYSLOGMAGIC 0xdeadbeaf
-#define SYSLOG ((Syslog *)(UNCACHED | 0x1B00))
-typedef struct Syslog Syslog;
-struct Syslog
-{
- ulong magic;
- int wrapped;
- char *next;
- char buf[2*1024];
-};
-
-
-void
-printinit(void)
-{
-
- printq.in = printq.buf;
- printq.out = printq.buf;
- lock(&printq); /* allocate lock */
- unlock(&printq);
+struct {
+ IOQ; /* lock to klogputs */
+ QLock; /* qlock to getc */
+} klogq;
- kbdq.in = kbdq.buf;
- kbdq.out = kbdq.buf;
- lineq.in = lineq.buf;
- lineq.out = lineq.buf;
- qlock(&kbdq); /* allocate qlock */
- qunlock(&kbdq);
- lock(&lineq); /* allocate lock */
- unlock(&lineq);
+IOQ lineq; /* lock to getc; interrupt putc's */
+IOQ printq;
+IOQ mouseq;
+KIOQ kbdq;
- duartinit();
-}
+Ref raw; /* whether kbd i/o is raw (rcons is open) */
/*
- * Put a string on the console.
- * n bytes of s are guaranteed to fit in the buffer and is ready to print.
- * Must be called splhi() and with printq locked.
+ * init the queues and set the output routine
*/
void
-puts(char *s, int n)
+printinit(void)
{
- if(!printq.printing){
- printq.printing = 1;
- printq.c = *s++;
- n--;
- }
- memmove(printq.in, s, n);
- printq.in += n;
- if(printq.in >= printq.buf+sizeof(printq.buf))
- printq.in = printq.buf;
+ initq(&printq);
+ initq(&lineq);
+ initq(&kbdq);
+ kbdq.putc = kbdputc;
+ initq(&klogq);
+ initq(&mouseq);
+ mouseq.putc = mouseputc;
}
/*
- * Print a string on the console. This is the high level routine
- * with a queue to the interrupt handler. BUG: There is no check against
- * overflow.
+ * Print a string on the console. Convert \n to \r\n
*/
void
putstrn(char *str, int n)
@@ 99,39 44,59 @@ putstrn(char *str, int n)
int s, c, m;
char *t;
- s = splhi();
- lock(&printq);
- syslog(str, n);
while(n > 0){
- if(*str == '\n')
- puts("\r", 1);
- m = printq.buf+sizeof(printq.buf) - printq.in;
- if(n < m)
- m = n;
+ if(printq.puts && *str=='\n')
+ (*printq.puts)(&printq, "\r", 1);
+ m = n;
t = memchr(str+1, '\n', m-1);
if(t)
if(t-str < m)
m = t - str;
- puts(str, m);
+ if(printq.puts)
+ (*printq.puts)(&printq, str, m);
+ screenputs(str, m);
n -= m;
str += m;
}
- unlock(&printq);
- splx(s);
}
-int
-cangetc(IOQ *q)
+/*
+ * Print a string in the kernel log. Ignore overflow.
+ */
+void
+klogputs(char *str, long n)
{
- return q->in != q->out;
+ int s, m;
+ uchar *nextin;
+
+ s = splhi();
+ lock(&klogq);
+ while(n){
+ m = &klogq.buf[NQ] - klogq.in;
+ if(m > n)
+ m = n;
+ memmove(klogq.in, str, m);
+ n -= m;
+ str += m;
+ nextin = klogq.in + m;
+ if(nextin >= &klogq.buf[NQ])
+ klogq.in = klogq.buf;
+ else
+ klogq.in = nextin;
+ }
+ unlock(&klogq);
+ splx(s);
+ wakeup(&klogq.r);
}
int
-isbrkc(IOQ *q)
+isbrkc(KIOQ *q)
{
uchar *p;
for(p=q->out; p!=q->in; ){
+ if(raw.ref)
+ return 1;
if(*p==0x04 || *p=='\n')
return 1;
p++;
@@ 142,19 107,6 @@ isbrkc(IOQ *q)
}
int
-getc(IOQ *q)
-{
- int c;
-
- if(q->in == q->out)
- return -1;
- c = *q->out++;
- if(q->out == q->buf+sizeof(q->buf))
- q->out = q->buf;
- return c;
-}
-
-int
sprint(char *s, char *fmt, ...)
{
return doprint(s, s+PRINTSIZE, fmt, (&fmt+1)) - s;
@@ 171,6 123,17 @@ print(char *fmt, ...)
return n;
}
+int
+kprint(char *fmt, ...)
+{
+ char buf[PRINTSIZE];
+ int n;
+
+ n = doprint(buf, buf+sizeof(buf), fmt, (&fmt+1)) - buf;
+ klogputs(buf, n);
+ return n;
+}
+
void
panic(char *fmt, ...)
{
@@ 212,55 175,50 @@ pprint(char *fmt, ...)
void
prflush(void)
{
- while(printq.printing)
- delay(100);
-}
-
-/*
- * Get character to print at interrupt time.
- * Always called splhi from proc 0.
- */
-int
-conschar(void)
-{
- uchar *p;
- int c;
-
- lock(&printq);
- p = printq.out;
- if(p == printq.in){
- printq.printing = 0;
- c = -1;
- }else{
- c = *p++;
- if(p >= printq.buf+sizeof(printq.buf))
- p = printq.buf;
- printq.out = p;
- }
- unlock(&printq);
- return c;
+ while(printq.in != printq.out) ;
}
void
echo(int c)
{
char ch;
+ static int ctrlt;
/*
- * ^t hack BUG
+ * ^p hack
*/
if(c == 0x10)
panic("^p");
- if(c == 0x14)
- DEBUG();
+ /*
+ * ^t hack BUG
+ */
+ if(ctrlt == 2){
+ ctrlt = 0;
+ switch(c){
+ case 0x14:
+ break; /* pass it on */
+ case 'm':
+ mntdump();
+ return;
+ case 'p':
+ DEBUG();
+ return;
+ case 'q':
+ dumpqueues();
+ return;
+ case 'r':
+ exit();
+ break;
+ }
+ }else if(c == 0x14){
+ ctrlt++;
+ return;
+ }
+ ctrlt = 0;
+ if(raw.ref)
+ return;
if(c == 0x15)
putstrn("^U\n", 3);
- if(c == 0x16)
- dumpqueues();
- if(c == 0xe)
- nonettoggle();
- if(c == 0xc)
- lancetoggle();
else{
ch = c;
putstrn(&ch, 1);
@@ 271,31 229,38 @@ echo(int c)
* Put character into read queue at interrupt time.
* Always called splhi from proc 0.
*/
-void
-kbdchar(int c)
+int
+kbdputc(IOQ *q, int ch)
{
- if(c == 0) /* NULs cause trouble */
- return;
- if(c == '\r')
- c = '\n';
- echo(c);
- *kbdq.in++ = c;
+ echo(ch);
+ kbdq.c = ch;
+ *kbdq.in++ = ch;
if(kbdq.in == kbdq.buf+sizeof(kbdq.buf))
kbdq.in = kbdq.buf;
- if(c=='\n' || c==0x04)
+ if(raw.ref || ch=='\n' || ch==0x04)
wakeup(&kbdq.r);
+ return 0;
}
void
-printslave(void)
+kbdrepeat(int rep)
{
- int c;
+ kbdq.repeat = rep;
+ kbdq.count = 0;
+}
- c = printq.c;
- if(c){
- printq.c = 0;
- duartxmit(c);
+void
+kbdclock(void)
+{
+ if(kbdq.repeat == 0)
+ return;
+ if(kbdq.repeat==1 && ++kbdq.count>HZ){
+ kbdq.repeat = 2;
+ kbdq.count = 0;
+ return;
}
+ if(++kbdq.count&1)
+ kbdputc(&kbdq, kbdq.c);
}
int
@@ 311,31 276,37 @@ enum{
Qdir,
Qcons,
Qcputime,
- Qlog,
+ Qlights,
+ Qnoise,
Qnull,
-/* Qpanic, /**/
Qpgrpid,
Qpid,
Qppid,
+ Qrcons,
Qtime,
Quser,
- Qvmereset,
+ Qklog,
+ Qmsec,
+ Qclock,
Qsysstat,
};
Dirtab consdir[]={
- "cons", {Qcons}, 0, 0600,
- "cputime", {Qcputime}, 72, 0600,
- "log", {Qlog}, BY2PG-8, 0600,
- "null", {Qnull}, 0, 0600,
-/* "panic", {Qpanic}, 0, 0666, /**/
- "pgrpid", {Qpgrpid}, 12, 0600,
- "pid", {Qpid}, 12, 0600,
- "ppid", {Qppid}, 12, 0600,
- "time", {Qtime}, 12, 0600,
- "user", {Quser}, 0, 0600,
- "vmereset", {Qvmereset}, 0, 0600,
- "sysstat", {Qsysstat}, 0, 0600,
+ "cons", {Qcons}, 0, 0600,
+ "cputime", {Qcputime}, 6*NUMSIZE, 0600,
+ "lights", {Qlights}, 0, 0600,
+ "noise", {Qnoise}, 0, 0600,
+ "null", {Qnull}, 0, 0600,
+ "pgrpid", {Qpgrpid}, NUMSIZE, 0600,
+ "pid", {Qpid}, NUMSIZE, 0600,
+ "ppid", {Qppid}, NUMSIZE, 0600,
+ "rcons", {Qrcons}, 0, 0600,
+ "time", {Qtime}, NUMSIZE, 0600,
+ "user", {Quser}, 0, 0600,
+ "klog", {Qklog}, 0, 0400,
+ "msec", {Qmsec}, NUMSIZE, 0400,
+ "clock", {Qclock}, 2*NUMSIZE, 0400,
+ "sysstat", {Qsysstat}, 0, 0600,
};
#define NCONS (sizeof consdir/sizeof(Dirtab))
@@ 415,12 386,29 @@ consstat(Chan *c, char *dp)
Chan*
consopen(Chan *c, int omode)
{
- if(c->qid.path==Quser && omode==(OWRITE|OTRUNC)){
- /* truncate? */
- if(strcmp(u->p->pgrp->user, "bootes") == 0) /* BUG */
- u->p->pgrp->user[0] = 0;
- else
- error(Eperm);
+ int ch;
+
+ switch(c->qid.path){
+ case Quser:
+ if(omode==(OWRITE|OTRUNC)){
+ /* truncate? */
+ if(strcmp(u->p->pgrp->user, "bootes") == 0) /* BUG */
+ u->p->pgrp->user[0] = 0;
+ else
+ error(Eperm);
+ }
+ break;
+ case Qrcons:
+ if(incref(&raw) == 1){
+ lock(&lineq);
+ while((ch=getc(&kbdq)) != -1){
+ *lineq.in++ = ch;
+ if(lineq.in == lineq.buf+sizeof(lineq.buf))
+ lineq.in = lineq.buf;
+ }
+ unlock(&lineq);
+ }
+ break;
}
return devopen(c, omode, consdir, NCONS, devgen);
}
@@ 434,8 422,11 @@ conscreate(Chan *c, char *name, int omode, ulong perm)
void
consclose(Chan *c)
{
+ if(c->qid.path==Qrcons && (c->flag&COPEN))
+ decref(&raw);
}
+
long
consread(Chan *c, void *buf, long n, ulong offset)
{
@@ 445,7 436,7 @@ consread(Chan *c, void *buf, long n, ulong offset)
char *cbuf = buf;
char *user;
int userlen;
- char tmp[6*NUMSIZE], xbuf[512];
+ char tmp[6*NUMSIZE], xbuf[1024];
Mach *mp;
if(n <= 0)
@@ 454,6 445,7 @@ consread(Chan *c, void *buf, long n, ulong offset)
case Qdir:
return devdirread(c, buf, n, consdir, NCONS, devgen);
+ case Qrcons:
case Qcons:
qlock(&kbdq);
if(waserror()){
@@ 461,9 453,14 @@ consread(Chan *c, void *buf, long n, ulong offset)
nexterror();
}
while(!cangetc(&lineq)){
- sleep(&kbdq.r, (int(*)(void*))isbrkc, &kbdq);
+ sleep(&kbdq.r, isbrkc, &kbdq);
do{
+ lock(&lineq);
ch = getc(&kbdq);
+ if(raw.ref){
+ unlock(&lineq);
+ goto Default;
+ }
switch(ch){
case '\b':
if(lineq.in != lineq.out){
@@ 475,17 472,21 @@ consread(Chan *c, void *buf, long n, ulong offset)
case 0x15:
lineq.in = lineq.out;
break;
+ Default:
default:
- *lineq.in++ = ch;
- if(lineq.in == lineq.buf+sizeof(lineq.buf))
- lineq.in = lineq.buf;
+ *lineq.in = ch;
+ if(lineq.in >= lineq.buf+sizeof(lineq.buf)-1)
+ lineq.in = lineq.buf;
+ else
+ lineq.in++;
}
- }while(ch!='\n' && ch!=0x04);
+ unlock(&lineq);
+ }while(raw.ref==0 && ch!='\n' && ch!=0x04);
}
i = 0;
- while(n>0){
+ while(n > 0){
ch = getc(&lineq);
- if(ch == 0x04 || ch == -1)
+ if(ch==-1 || (raw.ref==0 && ch==0x04))
break;
i++;
*cbuf++ = ch;
@@ 523,11 524,42 @@ consread(Chan *c, void *buf, long n, ulong offset)
case Qtime:
return readnum(offset, buf, n, boottime+TK2SEC(MACHP(0)->ticks), 12);
+ case Qclock:
+ k = offset;
+ if(k >= 2*NUMSIZE)
+ return 0;
+ if(k+n > 2*NUMSIZE)
+ n = 2*NUMSIZE - k;
+ readnum(0, tmp, NUMSIZE, MACHP(0)->ticks, NUMSIZE);
+ readnum(0, tmp+NUMSIZE, NUMSIZE, HZ, NUMSIZE);
+ memmove(buf, tmp+k, n);
+ return n;
+
case Quser:
return readstr(offset, buf, n, u->p->pgrp->user);
- case Qlog:
- return readlog(offset, buf, n);
+ case Qnull:
+ return 0;
+
+ case Qklog:
+ qlock(&klogq);
+ if(waserror()){
+ qunlock(&klogq);
+ nexterror();
+ }
+ while(!cangetc(&klogq))
+ sleep(&klogq.r, cangetc, &klogq);
+ for(i=0; i<n; i++){
+ if((ch=getc(&klogq)) == -1)
+ break;
+ *cbuf++ = ch;
+ }
+ poperror();
+ qunlock(&klogq);
+ return i;
+
+ case Qmsec:
+ return readnum(offset, buf, n, TK2MS(MACHP(0)->ticks), NUMSIZE);
case Qsysstat:
j = 0;
@@ 536,13 568,10 @@ consread(Chan *c, void *buf, long n, ulong offset)
mp = MACHP(id);
j += sprint(&xbuf[j], "%d %d %d %d %d %d %d %d\n",
id, mp->cs, mp->intr, mp->syscall, mp->pfault,
- mp->tlbfault, mp->tlbpurge, mp->spinlock);
+ mp->tlbfault, mp->tlbpurge, m->spinlock);
}
}
-
return readstr(offset, buf, n, xbuf);
- case Qnull:
- return 0;
default:
panic("consread %lux\n", c->qid);
@@ 550,17 579,60 @@ consread(Chan *c, void *buf, long n, ulong offset)
}
}
+void
+conslights(char *a, int n)
+{
+ int l;
+ char line[128];
+ char *lp;
+ int c;
+
+ lp = line;
+ while(n--){
+ *lp++ = c = *a++;
+ if(c=='\n' || n==0 || lp==&line[sizeof(line)-1])
+ break;
+ }
+ *lp = 0;
+ lights(strtoul(line, 0, 0));
+}
+
+void
+consnoise(char *a, int n)
+{
+ int freq;
+ int duration;
+ char line[128];
+ char *lp;
+ int c;
+
+ lp = line;
+ while(n--){
+ *lp++ = c = *a++;
+ if(c=='\n' || n==0 || lp==&line[sizeof(line)-1]){
+ *lp = 0;
+ freq = strtoul(line, &lp, 0);
+ while(*lp==' ' || *lp=='\t')
+ lp++;
+ duration = strtoul(lp, &lp, 0);
+ buzz(freq, duration);
+ lp = line;
+ }
+ }
+}
+
long
conswrite(Chan *c, void *va, long n, ulong offset)
{
char cbuf[64];
char buf[256];
long l, m;
- int id;
char *a = va;
Mach *mp;
+ int id;
switch(c->qid.path){
+ case Qrcons:
case Qcons:
/*
* Damn. Can't page fault in putstrn, so copy the data locally.
@@ 607,11 679,14 @@ conswrite(Chan *c, void *va, long n, ulong offset)
case Qnull:
break;
- case Qvmereset:
- if(strcmp(u->p->pgrp->user, "bootes") != 0)
- error(Eperm);
- vmereset();
+ case Qnoise:
+ consnoise(a, n);
break;
+
+ case Qlights:
+ conslights(a, n);
+ break;
+
case Qsysstat:
for(id = 0; id < 32; id++) {
if(active.machs & (1<<id)) {
@@ 625,8 700,8 @@ conswrite(Chan *c, void *va, long n, ulong offset)
mp->spinlock = 0;
}
}
-
break;
+
default:
error(Egreg);
}
@@ 644,119 719,3 @@ conswstat(Chan *c, char *dp)
{
error(Eperm);
}
-
-/*
- * kernel based system log, passed between crashes
- */
-void
-sysloginit(void)
-{
- Syslog *s;
- int i;
-
- s = SYSLOG;
- if(s->magic!=SYSLOGMAGIC || s->next>=&s->buf[sizeof(s->buf)] || s->next<s->buf){
- s->wrapped = 0;
- s->next = s->buf;
- s->magic = SYSLOGMAGIC;
- }
-}
-
-void
-syslog(char *p, int n)
-{
- Syslog *s;
- char *end;
- int m;
-
- sysloginit();
- s = SYSLOG;
- end = &s->buf[sizeof(s->buf)];
- while(n){
- if(s->next + n > end)
- m = end - s->next;
- else
- m = n;
- memmove(s->next, p, m);
- s->next += m;
- p += m;
- n -= m;
- if(s->next >= end){
- s->wrapped = 1;
- s->next = s->buf;
- }
- }
- wbflush();
-}
-
-long
-readlog(ulong off, char *buf, ulong len)
-{
- Syslog *s;
- char *end;
- char *start;
- int n, m;
- char *p;
-
- n = len;
- p = buf;
-
- sysloginit();
- s = SYSLOG;
- end = &s->buf[sizeof(s->buf)];
-
- if(s->wrapped){
- start = s->next;
- m = sizeof(s->buf);
- } else {
- start = s->buf;
- m = s->next - start;
- }
-
- if(off > m)
- return 0;
- if(off + n > m)
- n = m - off;
- start += off;
- if(start > end)
- start -= sizeof(s->buf);
-
- while(n > 0){
- if(start + n > end)
- m = end - start;
- else
- m = n;
- memmove(p, start, m);
- start += m;
- p += m;
- n -= m;
- if(start >= end)
- start = s->buf;
- }
-
- return p-buf;
-}
-
-/*
- * Read and write every byte of the log. This seems to ensure that
- * on reboot, the bytes will really be in memory. I don't understand -- presotto
- */
-void
-flushsyslog(void)
-{
- Syslog *s;
- char *p, *end;
- int x;
-
- s = SYSLOG;
- end = &s->buf[sizeof(s->buf)];
-
- x = splhi();
- lock(&printq);
- for(p = s->buf; p < end; p++)
- *p = *p;
- unlock(&printq);
- splx(x);
-
- wbflush();
-}
M port/devscc.c => port/devscc.c +0 -3
@@ 284,7 284,6 @@ sccintr0(SCC *sp, uchar x)
IOQ *cq;
if(x & ExtPendB){
- /*kprint("scc %d: %2.2ux\n", sp-scc, *sp->ptr);*/
sccwrreg(sp, 0, ResExtPend);
}
if(x & RxPendB){
@@ 305,10 304,8 @@ sccintr0(SCC *sp, uchar x)
cq = sp->oq;
lock(cq);
ch = getc(cq);
- /*kprint("<%2.2ux>", ch);*/
onepointseven();
if(ch < 0){
- /*kprint("<done>", ch);*/
sccwrreg(sp, 0, ResTxPend);
sp->printing = 0;
wakeup(&cq->r);
M port/fault.c => port/fault.c +22 -10
@@ 9,7 9,7 @@
int
fault(ulong addr, int read)
{
- ulong mmuvirt, mmuphys = 0, n;
+ ulong mmuvirt, mmuphys, uncache = 0, n;
Seg *s;
PTE *opte, *pte, *npte;
Orig *o;
@@ 67,7 67,11 @@ fault(ulong addr, int read)
/* Make a new bss or lock segment page */
if(s - u->p->seg == LSEG) {
pte->page = lkpage(o, addr);
- mmuphys = PTEUNCACHE;
+ if(pte->page == 0) {
+ unlock(o);
+ return -1;
+ }
+ uncache = PTEUNCACHED;
}
else
pte->page = newpage(0, o, addr);
@@ 115,9 119,12 @@ fault(ulong addr, int read)
/*
* Copy on reference (conf.copymode==1) or write (conf.copymode==0)
*/
- if((o->flag & OWRPERM) && (conf.copymode || !read)
+ if((o->flag & (OWRPERM|OSHARED))==OWRPERM && (conf.copymode || !read)
&& ((head && ((o->flag&OPURE) || o->nproc>1))
|| (!head && pte->page->ref>1))){
+
+ if(!(o->flag&OISMEM))
+ panic("copy on ref/wr to non memory");
touched = 1;
/*
* Look for the easy way out: are we the last non-modified?
@@ 163,6 170,7 @@ fault(ulong addr, int read)
* increment on the mod list which must be removed
*/
if(zeroed){
+ pg->ref--;
o->npage--;
opte->page = 0;
}else{ /* copy page */
@@ 174,25 182,27 @@ fault(ulong addr, int read)
kunmap(k1);
if(pg->ref <= 1)
panic("pg->ref <= 1");
+ pg->ref--;
}
- pg->ref--;
easy:
- mmuphys |= PTEWRITE;
+ mmuphys = PTEWRITE;
}else{
- mmuphys |= PTERONLY;
+ mmuphys = PTERONLY;
if(o->flag & OWRPERM)
if(o->flag & OPURE){
if(!head && pte->page->ref==1)
- mmuphys |= PTEWRITE;
+ mmuphys = PTEWRITE;
}else
if((head && o->nproc==1)
|| (!head && pte->page->ref==1))
- mmuphys |= PTEWRITE;
+ mmuphys = PTEWRITE;
}
mmuvirt = addr;
- mmuphys |= PPN(pte->page->pa) | PTEVALID;
- usepage(pte->page, 1);
+ mmuphys |= PPN(pte->page->pa) | PTEVALID | uncache;
+ if(o->flag&OISMEM)
+ usepage(pte->page, 1);
+
if(pte->page->va != addr)
panic("wrong addr in tail %lux %lux", pte->page->va, addr);
if(pte->proc && pte->proc != u->p){
@@ 200,9 210,11 @@ fault(ulong addr, int read)
print("u->p %lux pte->proc %lux\n", u->p, pte->proc);
panic("addr %lux seg %d wrong proc in tail", addr, s-u->p->seg);
}
+
unlock(o);
if(touched == 0)
m->tlbfault++;
+
putmmu(mmuvirt, mmuphys);
return 0;
}
M port/page.c => port/page.c +4 -4
@@ 334,6 334,7 @@ loop:
o->nproc = 1;
o->npage = 0;
o->chan = c;
+ o->freepg = unusepage;
if(c){
o->type = c->type;
o->qid = c->qid;
@@ 428,8 429,6 @@ forkmod(Seg *old, Seg *new, Proc *p)
ppte = 0;
pte = old->mod;
while(pte){
-if(pte->page==0) panic("forkmod zero page");
-if(pte->proc != u->p) panic("forkmod wrong page");
npte = newmod(o);
npte->proc = p;
npte->page = pte->page;
@@ 579,15 578,16 @@ freepage(Orig *o, int dolock)
int i;
pte = o->pte;
- for(i=0; i<o->npte; i++,pte++)
+ for(i=0; i<o->npte; i++,pte++) {
if(pg = pte->page){ /* assign = */
if(pg->ref == 1){
- unusepage(pg, dolock);
+ (*o->freepg)(pg, dolock);
pte->page = 0;
pg->o = 0;
}
pg->ref--;
}
+ }
o->npage = 0;
}
M port/portdat.h => port/portdat.h +37 -1
@@ 9,6 9,8 @@ typedef struct Env Env;
typedef struct Envp Envp;
typedef struct Envval Envval;
typedef struct Etherpkt Etherpkt;
+typedef struct IOQ IOQ;
+typedef struct KIOQ KIOQ;
typedef struct List List;
typedef struct Mount Mount;
typedef struct Mtab Mtab;
@@ 199,6 201,37 @@ struct Etherpkt {
#define ETHERMAXTU 1514 /* maximum transmit size */
#define ETHERHDRSIZE 14 /* size of an ethernet header */
+/*
+ * character based IO (mouse, keyboard, console screen)
+ */
+#define NQ 4096
+struct IOQ
+{
+ Lock;
+ uchar buf[NQ];
+ uchar *in;
+ uchar *out;
+ int state;
+ Rendez r;
+ union{
+ void (*puts)(IOQ*, void*, int); /* output */
+ int (*putc)(IOQ*, int); /* input */
+ };
+ void *ptr;
+};
+struct KIOQ
+{
+ QLock;
+ IOQ;
+ int repeat;
+ int c;
+ int count;
+};
+extern IOQ lineq;
+extern IOQ printq;
+extern IOQ mouseq;
+extern KIOQ kbdq;
+
struct Mount
{
Ref; /* also used as a lock when playing lists */
@@ 229,6 262,8 @@ struct Note
#define OWRPERM 0x01 /* write permission */
#define OPURE 0x02 /* original data mustn't be written */
#define OCACHED 0x04 /* cached; don't discard on exit */
+#define OISMEM 0x08 /* origin contains real memory */
+#define OSHARED 0x10 /* origin does not copy on ref/wr */
struct Orig
{
@@ 247,6 282,8 @@ struct Orig
Qid mqid;
ulong minca; /* base of region in chan */
ulong maxca; /* end of region in chan */
+ void (*freepg)(Page*, int); /* how to free pages for this origin */
+ Page (*allocpg)(int, Orig*, ulong);
};
struct Page
@@ 298,7 335,6 @@ struct Seg
ulong maxva; /* va of last pte */
PTE *mod; /* list of modified pte's */
ulong endseg; /* segments end */
- ulong pad[2]; /**/
};
/*
M port/portfns.h => port/portfns.h +20 -1
@@ 10,8 10,10 @@ int blen(Block *);
int bround(Block *, int);
void buzz(int, int);
void cancel(Alarm*);
+int cangetc(void*);
int canlock(Lock*);
int canqlock(QLock*);
+int canputc(void*);
void chandevinit(void);
void chandevreset(void);
void chaninit(void);
@@ 65,19 67,27 @@ void freepage(Orig*, int);
void freepte(Orig*);
void freesegs(int);
Block* getb(Blist*);
+int getc(IOQ*);
int getfields(char*, char**, int, char);
Block* getq(Queue*);
+int gets(IOQ*, void*, int);
void gotolabel(Label*);
void growpte(Orig*, ulong);
void* ialloc(ulong, int);
long ibrk(ulong, int);
int incref(Ref*);
+void initq(IOQ*);
void insert(List**, List*, List*);
void invalidateu(void);
void isdir(Chan*);
+void kbdclock(void);
+void kbdrepeat(int);
+int kbdputc(IOQ*, int);
+int kprint(char*, ...);
void kproc(char*, void(*)(void*), void*);
void lights(int);
Page* lkpage(Orig*, ulong);
+void lkpgfree(Page*, int);
void lock(Lock*);
void lockinit(void);
Orig* lookorig(ulong, ulong, int, Chan*);
@@ 86,6 96,7 @@ void mapstack(Proc*);
void mklockseg(Seg*);
void mmurelease(Proc*);
int mount(Chan*, Chan*, int);
+int mouseputc(IOQ*, int);
Chan* namec(char*, int, int, ulong);
Alarm* newalarm(void);
Chan* newchan(void);
@@ 112,7 123,11 @@ Pgrp* pgrptab(int);
#define poperror() u->nerrlab--
int postnote(Proc*, int, char*, int);
int pprint(char*, ...);
-void printslave(void);
+void printinit(void);
+int putc(IOQ*, int);
+void putstr(char*);
+void putstrn(char*, long);
+void puts(IOQ*, void*, int);
ulong procalarm(ulong);
void procinit0(void);
Proc* proctab(int);
@@ 131,6 146,10 @@ void resched(char*);
int return0(void*);
Proc* runproc(void);
void savefpregs(FPsave*);
+void sccintr(void);
+void sccputs(IOQ*, char*, int);
+void sccsetup(void*);
+void sccspecial(int, IOQ*, IOQ*, int);
void schedinit(void);
void sched(void);
long seconds(void);
M port/sysproc.c => port/sysproc.c +7 -7
@@ 66,7 66,7 @@ sysfork(ulong *arg)
usp = s->minva & (BY2PG-1); /* just low bits */
s->maxva = USTKTOP;
n = (s->maxva-s->minva)>>PGSHIFT;
- s->o = neworig(s->minva, n, OWRPERM, 0);
+ s->o = neworig(s->minva, n, OWRPERM|OISMEM, 0);
lock(s->o);
/*
* Only part of last stack page
@@ 250,7 250,7 @@ sysexec(ulong *arg)
s = &p->seg[ESEG];
s->proc = p;
- s->o = neworig(TSTKTOP-(spage<<PGSHIFT), spage, OWRPERM, 0);
+ s->o = neworig(TSTKTOP-(spage<<PGSHIFT), spage, OWRPERM|OISMEM, 0);
s->minva = s->o->va;
s->maxva = TSTKTOP;
@@ 295,9 295,9 @@ sysexec(ulong *arg)
*/
s = &p->seg[TSEG];
s->proc = p;
- o = lookorig(UTZERO, (t-UTZERO)>>PGSHIFT, OCACHED, tc);
+ o = lookorig(UTZERO, (t-UTZERO)>>PGSHIFT, OCACHED|OISMEM, tc);
if(o == 0){
- o = neworig(UTZERO, (t-UTZERO)>>PGSHIFT, OCACHED, tc);
+ o = neworig(UTZERO, (t-UTZERO)>>PGSHIFT, OCACHED|OISMEM, tc);
o->minca = 0;
o->maxca = sizeof(Exec)+exec.text;
}
@@ 311,9 311,9 @@ sysexec(ulong *arg)
*/
s = &p->seg[DSEG];
s->proc = p;
- o = lookorig(t, (d-t)>>PGSHIFT, OWRPERM|OPURE|OCACHED, tc);
+ o = lookorig(t, (d-t)>>PGSHIFT, OWRPERM|OPURE|OCACHED|OISMEM, tc);
if(o == 0){
- o = neworig(t, (d-t)>>PGSHIFT, OWRPERM|OPURE|OCACHED, tc);
+ o = neworig(t, (d-t)>>PGSHIFT, OWRPERM|OPURE|OCACHED|OISMEM, tc);
o->minca = p->seg[TSEG].o->maxca;
o->maxca = o->minca + exec.data;
}
@@ 327,7 327,7 @@ sysexec(ulong *arg)
*/
s = &p->seg[BSEG];
s->proc = p;
- o = neworig(d, (b-d)>>PGSHIFT, OWRPERM, 0);
+ o = neworig(d, (b-d)>>PGSHIFT, OWRPERM|OISMEM, 0);
o->minca = 0;
o->maxca = 0;
s->o = o;
M power/clock.c => power/clock.c +1 -1
@@ 101,8 101,8 @@ clock(Ureg *ur)
p->time[p->insyscall]++;
}
}
- printslave();
}
+ duartslave();
if(active.exiting && active.machs&(1<<m->machno)){
print("someone's exiting\n");
exit();
A power/devduart.c => power/devduart.c +836 -0
@@ 0,0 1,836 @@
+#include "u.h"
+#include "lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+
+int duartacr;
+int duartimr;
+
+void duartputs(IOQ*, char*, int);
+void iprint(char*, ...);
+
+#define PAD 15 /* registers are well-spaced */
+
+/*
+ * Register set for half the duart. There are really two sets.
+ */
+struct Duart{
+ uchar mr1_2, /* Mode Register Channels 1 & 2 */
+ pad0[PAD];
+ uchar sr_csr, /* Status Register/Clock Select Register */
+ pad1[PAD];
+ uchar cmnd, /* Command Register */
+ pad2[PAD];
+ uchar data, /* RX Holding / TX Holding Register */
+ pad3[PAD];
+ uchar ipc_acr, /* Input Port Change/Aux. Control Register */
+ pad4[PAD];
+ uchar is_imr, /* Interrupt Status/Interrupt Mask Register */
+ pad5[PAD];
+ uchar ctur, /* Counter/Timer Upper Register */
+ pad6[PAD];
+ uchar ctlr, /* Counter/Timer Lower Register */
+ pad7[PAD];
+};
+#define ppcr is_imr /* in the second register set */
+
+#define DBD75 0
+#define DBD110 1
+#define DBD38400 2
+#define DBD150 3
+#define DBD300 4
+#define DBD600 5
+#define DBD1200 6
+#define DBD2000 7
+#define DBD2400 8
+#define DBD4800 9
+#define DBD1800 10
+#define DBD9600 11
+#define DBD19200 12
+
+enum{
+ CHAR_ERR =0x00, /* MR1x - Mode Register 1 */
+ EVEN_PAR =0x00,
+ ODD_PAR =0x04,
+ NO_PAR =0x10,
+ CBITS8 =0x03,
+ CBITS7 =0x02,
+ CBITS6 =0x01,
+ CBITS5 =0x00,
+ NORM_OP =0x00, /* MR2x - Mode Register 2 */
+ TWOSTOPB =0x0F,
+ ONESTOPB =0x07,
+ ENB_RX =0x01, /* CRx - Command Register */
+ DIS_RX =0x02,
+ ENB_TX =0x04,
+ DIS_TX =0x08,
+ RESET_MR =0x10,
+ RESET_RCV =0x20,
+ RESET_TRANS =0x30,
+ RESET_ERR =0x40,
+ RESET_BCH =0x50,
+ STRT_BRK =0x60,
+ STOP_BRK =0x70,
+ RCV_RDY =0x01, /* SRx - Channel Status Register */
+ FIFOFULL =0x02,
+ XMT_RDY =0x04,
+ XMT_EMT =0x08,
+ OVR_ERR =0x10,
+ PAR_ERR =0x20,
+ FRM_ERR =0x40,
+ RCVD_BRK =0x80,
+ IM_IPC =0x80, /* IMRx/ISRx - Interrupt Mask/Interrupt Status */
+ IM_DBB =0x40,
+ IM_RRDYB =0x20,
+ IM_XRDYB =0x10,
+ IM_CRDY =0x08,
+ IM_DBA =0x04,
+ IM_RRDYA =0x02,
+ IM_XRDYA =0x01,
+ BD38400 =0xCC|0x0000,
+ BD19200 =0xCC|0x0100,
+ BD9600 =0xBB|0x0000,
+ BD4800 =0x99|0x0000,
+ BD2400 =0x88|0x0000,
+ BD1200 =0x66|0x0000,
+ BD300 =0x44|0x0000,
+
+ Maxport =8,
+};
+
+/*
+ * requests to perform on a duart
+ */
+enum {
+ Dnone= 0,
+ Dbaud,
+ Dbreak,
+ Ddtr,
+ Dprint,
+ Dena,
+ Dstate,
+};
+
+/*
+ * software info for a serial duart interface
+ */
+typedef struct Duartport Duartport;
+struct Duartport
+{
+ QLock;
+ int printing; /* true if printing */
+ Duart *duart; /* device */
+ int inited;
+ int c; /* character to restart output */
+ int op; /* operation requested */
+ int val; /* value of operation */
+ Rendez opr; /* waiot here for op to complete */
+
+ /* console interface */
+ int nostream; /* can't use the stream interface */
+ IOQ *iq; /* input character queue */
+ IOQ *oq; /* output character queue */
+
+ /* stream interface */
+ Queue *wq; /* write queue */
+ Rendez r; /* kproc waiting for input */
+ Alarm *a; /* alarm for waking the kernel process */
+ int delay; /* between character input and waking kproc */
+ int kstarted; /* kproc started */
+ uchar delim[256/8]; /* characters that act as delimiters */
+};
+Duartport duartport[Maxport]; /* max possible */
+
+/*
+ * configure a duart port, default is 9600 baud, 8 bits/char, 1 stop bit,
+ * no parity
+ */
+void
+duartsetup(Duartport *dp)
+{
+ Duart *duart;
+
+ duart = dp->duart;
+
+ duart->cmnd = RESET_RCV|DIS_TX|DIS_RX;
+ duart->cmnd = RESET_TRANS;
+ duart->cmnd = RESET_ERR;
+ duart->cmnd = STOP_BRK;
+
+ duart->ipc_acr = 0x80; /* baud-rate set 2 */
+ duart->cmnd = RESET_MR;
+ duart->mr1_2 = NO_PAR|CBITS8;
+ duart->mr1_2 = ONESTOPB;
+ duart->sr_csr = (DBD9600<<4)|DBD9600;
+ duart->is_imr = IM_RRDYA|IM_XRDYA;
+ duart->cmnd = ENB_TX|ENB_RX;
+}
+
+/*
+ * init the duart on the current processor
+ */
+void
+duartinit(void)
+{
+ Duartport *dp;
+
+ dp = &duartport[2*m->machno];
+ if(dp->inited)
+ return;
+ dp->inited = 1;
+
+ dp->duart = DUARTREG;
+ duartsetup(dp);
+ dp++;
+ dp->duart = DUARTREG+1;
+ duartsetup(dp);
+}
+
+/*
+ * enable a duart port
+ */
+void
+duartenable(Duartport *dp)
+{
+ dp->duart->cmnd = ENB_TX|ENB_RX;
+}
+
+void
+duartenable0(void)
+{
+ DUARTREG->cmnd = ENB_TX|ENB_RX;
+}
+
+void
+duartbaud(Duartport *dp, int b)
+{
+ int x = 0;
+
+ switch(b){
+ case 38400:
+ x = BD38400;
+ break;
+ case 19200:
+ x = BD19200;
+ break;
+ case 9600:
+ x = BD9600;
+ break;
+ case 4800:
+ x = BD4800;
+ break;
+ case 2400:
+ x = BD2400;
+ break;
+ case 1200:
+ x = BD1200;
+ break;
+ case 300:
+ x = BD300;
+ break;
+ default:
+ errors("bad baud rate");
+ }
+ if(x & 0x0100)
+ dp->duart->ipc_acr = duartacr |= 0x80;
+ else
+ dp->duart->ipc_acr = duartacr &= ~0x80;
+ dp->duart->sr_csr = x;
+}
+
+void
+duartdtr(Duartport *dp, int val)
+{
+ if (val)
+ dp->duart->ctlr=0x01;
+ else
+ dp->duart->ctur=0x01;
+}
+
+void
+duartbreak(Duartport *dp, int val)
+{
+ Duart *duart;
+
+ duart = dp->duart;
+ if (val){
+ duart->is_imr = duartimr &= ~IM_XRDYB;
+ duart->cmnd = STRT_BRK|ENB_TX;
+ } else {
+ duart->cmnd = STOP_BRK|ENB_TX;
+ duart->is_imr = duartimr |= IM_XRDYB;
+ }
+}
+
+/*
+ * do anything requested for this CPU's duarts
+ */
+void
+duartslave0(Duartport *dp)
+{
+ switch(dp->op){
+ case Ddtr:
+ duartbaud(dp, dp->val);
+ break;
+ case Dbaud:
+ duartdtr(dp, dp->val);
+ break;
+ case Dbreak:
+ duartbreak(dp, dp->val);
+ break;
+ case Dprint:
+ dp->duart->cmnd = ENB_TX;
+ dp->duart->data = dp->val;
+ break;
+ case Dena:
+ duartenable(dp);
+ break;
+ case Dstate:
+ dp->val = dp->duart->is_imr;
+ break;
+ }
+ dp->op = Dnone;
+ wakeup(&dp->opr);
+}
+void
+duartslave(void)
+{
+ Duartport *dp;
+
+ dp = &duartport[2*m->machno];
+ if(dp->op != Dnone)
+ duartslave0(dp);
+ dp++;
+ if(dp->op != Dnone)
+ duartslave0(dp);
+}
+
+duartrintr(Duartport *dp)
+{
+ Duart *duart;
+ IOQ *cq;
+ int status;
+ char ch;
+
+ duart = dp->duart;
+ status = duart->sr_csr;
+ ch = duart->data;
+ if(status & (FRM_ERR|OVR_ERR|PAR_ERR))
+ duart->cmnd = RESET_ERR;
+
+ cq = dp->iq;
+ if(cq->putc)
+ (*cq->putc)(cq, ch);
+ else {
+ putc(cq, ch);
+ if(dp->delim[ch/8] & (1<<(ch&7)) )
+ wakeup(&cq->r);
+ }
+}
+
+duartxintr(Duartport *dp)
+{
+ Duart *duart;
+ IOQ *cq;
+ char ch;
+
+ cq = dp->oq;
+ lock(cq);
+ ch = getc(cq);
+ duart = dp->duart;
+ if(ch < 0){
+ dp->printing = 0;
+ wakeup(&cq->r);
+ duart->cmnd = DIS_TX;
+ } else
+ duart->data = ch;
+ unlock(cq);
+}
+
+void
+duartintr(void)
+{
+ int cause, status, c;
+ Duart *duart;
+ Duartport *dp;
+
+ dp = &duartport[2*m->machno];
+ duart = dp->duart;
+ cause = duart->is_imr;
+ /*
+ * I can guess your interrupt.
+ */
+ /*
+ * Is it 1?
+ */
+ if(cause & IM_RRDYA)
+ duartrintr(dp);
+ /*
+ * Is it 2?
+ */
+ if(cause & IM_XRDYA)
+ duartxintr(dp);
+ /*
+ * Is it 3?
+ */
+ if(cause & IM_RRDYB)
+ duartrintr(dp+1);
+ /*
+ * Is it 4?
+ */
+ if(cause & IM_XRDYB)
+ duartxintr(dp+1);
+}
+
+/*
+ * processor 0 only
+ */
+int
+duartrawputc(int c)
+{
+ Duart *duart;
+ int i;
+
+ duart = DUARTREG;
+ if(c == '\n')
+ duartrawputc('\r');
+ duart->cmnd = ENB_TX;
+ i = 0;
+ while((duart->sr_csr&XMT_RDY) == 0)
+ if(++i >= 1000000){
+ duartsetup(&duartport[0]);
+ for(i=0; i<100000; i++)
+ ;
+ break;
+ }
+ duart->data = c;
+ if(c == '\n')
+ for(i=0; i<100000; i++)
+ ;
+ return c;
+}
+void
+duartrawputs(char *s)
+{
+ int i;
+ while(*s){
+ duartrawputc(*s++);
+ }
+ for(i=0; i < 1000000; i++)
+ ;
+}
+void
+iprint(char *fmt, ...)
+{
+ char buf[1024];
+ long *arg;
+
+ arg = (long*)(&fmt+1);
+ sprint(buf, fmt, *arg, *(arg+1), *(arg+2), *(arg+3));
+ duartrawputs(buf);
+}
+
+/*
+ * Queue n characters for output; if queue is full, we lose characters.
+ * Get the output going if it isn't already.
+ */
+void
+duartputs(IOQ *cq, char *s, int n)
+{
+ int ch, x;
+ Duartport *dp;
+ Duart *duart;
+
+ x = splhi();
+ lock(cq);
+ puts(cq, s, n);
+ dp = cq->ptr;
+ if(dp->printing == 0){
+ ch = getc(cq);
+ if(ch >= 0){
+ dp->printing = 1;
+ dp->val = ch;
+ dp->op = Dprint;
+ }
+ }
+ unlock(cq);
+ splx(x);
+}
+
+/*
+ * set up an duart port as something other than a stream
+ */
+void
+duartspecial(int port, IOQ *oq, IOQ *iq, int baud)
+{
+ Duartport *dp = &duartport[port];
+
+ dp->nostream = 1;
+ if(oq){
+ dp->oq = oq;
+ dp->oq->puts = duartputs;
+ dp->oq->ptr = dp;
+ }
+ if(iq){
+ dp->iq = iq;
+ dp->iq->ptr = dp;
+ }
+ duartenable(dp);
+ duartbaud(dp, baud);
+}
+
+static void duarttimer(Alarm*);
+static int duartputc(IOQ *, int);
+static void duartstopen(Queue*, Stream*);
+static void duartstclose(Queue*);
+static void duartoput(Queue*, Block*);
+static void duartkproc(void *);
+Qinfo duartinfo =
+{
+ nullput,
+ duartoput,
+ duartstopen,
+ duartstclose,
+ "duart"
+};
+
+/*
+ * wakeup the helper process to do input
+ */
+static void
+duarttimer(Alarm *a)
+{
+ Duartport *dp = a->arg;
+
+ cancel(a);
+ dp->a = 0;
+ wakeup(&dp->iq->r);
+}
+
+static int
+duartputc(IOQ *cq, int ch)
+{
+ Duartport *dp = cq->ptr; int r;
+
+ r = putc(cq, ch);
+
+ /*
+ * pass upstream within dp->delay milliseconds
+ */
+ if(dp->a==0){
+ if(dp->delay == 0)
+ wakeup(&cq->r);
+ else
+ dp->a = alarm(dp->delay, duarttimer, dp);
+ }
+ return r;
+}
+
+static void
+duartstopen(Queue *q, Stream *s)
+{
+ Duartport *dp;
+ char name[NAMELEN];
+
+ dp = &duartport[s->id];
+
+ qlock(dp);
+ dp->wq = WR(q);
+ WR(q)->ptr = dp;
+ RD(q)->ptr = dp;
+ dp->delay = 64;
+ dp->iq->putc = duartputc;
+ qunlock(dp);
+
+ /* start with all characters as delimiters */
+ memset(dp->delim, 1, sizeof(dp->delim));
+
+ if(dp->kstarted == 0){
+ dp->kstarted = 1;
+ sprint(name, "duart%d", s->id);
+ kproc(name, duartkproc, dp);
+ }
+}
+
+static void
+duartstclose(Queue *q)
+{
+ Duartport *dp = q->ptr;
+
+ qlock(dp);
+ dp->wq = 0;
+ dp->iq->putc = 0;
+ WR(q)->ptr = 0;
+ RD(q)->ptr = 0;
+ qunlock(dp);
+}
+
+static int
+opdone(void *x)
+{
+ Duartport *dp = x;
+
+ return dp->op == Dnone;
+}
+static void
+duartoput(Queue *q, Block *bp)
+{
+ Duartport *dp = q->ptr;
+ IOQ *cq;
+ int n, m;
+
+ if(dp == 0){
+ freeb(bp);
+ return;
+ }
+ cq = dp->oq;
+ if(waserror()){
+ freeb(bp);
+ nexterror();
+ }
+ if(bp->type == M_CTL){
+ qlock(dp);
+ while (cangetc(cq)) /* let output drain */
+ sleep(&cq->r, cangetc, cq);
+ n = strtoul((char *)(bp->rptr+1), 0, 0);
+ switch(*bp->rptr){
+ case 'B':
+ case 'b':
+ dp->val = n;
+ dp->op = Dbaud;
+ sleep(&dp->opr, opdone, dp);
+ break;
+ case 'D':
+ case 'd':
+ dp->val = n;
+ dp->op = Ddtr;
+ sleep(&dp->opr, opdone, dp);
+ break;
+ case 'K':
+ case 'k':
+ dp->val = 1;
+ dp->op = Dbreak;
+ sleep(&dp->opr, opdone, dp);
+ tsleep(&dp->opr, return0, 0, n);
+ dp->val = 0;
+ dp->op = Dbreak;
+ sleep(&dp->opr, opdone, dp);
+ break;
+ case 'R':
+ case 'r':
+ /* can't control? */
+ break;
+ case 'W':
+ case 'w':
+ if(n>=0 && n<1000)
+ dp->delay = n;
+ break;
+ }
+ qunlock(dp);
+ }else while((m = BLEN(bp)) > 0){
+ while ((n = canputc(cq)) == 0){
+ kprint(" duartoput: sleeping\n");
+ sleep(&cq->r, canputc, cq);
+ }
+ if(n > m)
+ n = m;
+ (*cq->puts)(cq, bp->rptr, n);
+ bp->rptr += n;
+ }
+ freeb(bp);
+ poperror();
+}
+
+/*
+ * process to send bytes upstream for a port
+ */
+static void
+duartkproc(void *a)
+{
+ Duartport *dp = a;
+ IOQ *cq = dp->iq;
+ Block *bp;
+ int n;
+
+loop:
+ while ((n = cangetc(cq)) == 0)
+ sleep(&cq->r, cangetc, cq);
+ qlock(dp);
+ if(dp->wq == 0){
+ cq->out = cq->in;
+ }else{
+ bp = allocb(n);
+ bp->flags |= S_DELIM;
+ bp->wptr += gets(cq, bp->wptr, n);
+ PUTNEXT(RD(dp->wq), bp);
+ }
+ qunlock(dp);
+ goto loop;
+}
+
+Dirtab *duartdir;
+int nduartport;
+
+/*
+ * allocate the queues if no one else has
+ */
+void
+duartreset(void)
+{
+ Duartport *dp;
+ int i;
+
+ /*
+ * allocate the directory and fill it in
+ */
+ nduartport = 2*conf.nmach;
+ duartdir = ialloc(nduartport*2*sizeof(Dirtab), 0);
+ for(i = 0; i < nduartport; i++){
+ sprint(duartdir[2*i].name, "tty%d", i);
+ sprint(duartdir[2*i+1].name, "tty%dctl", i);
+ duartdir[2*i].length = duartdir[2*i+1].length = 0;
+ duartdir[2*i].perm = duartdir[2*i+1].perm = 0666;
+ duartdir[2*i].qid.path = STREAMQID(i, Sdataqid);
+ duartdir[2*i+1].qid.path = STREAMQID(i, Sctlqid);
+ }
+
+ /*
+ * allocate queues for any stream interfaces
+ */
+ for(dp = duartport; dp < &duartport[nduartport]; dp++){
+ if(dp->nostream)
+ continue;
+
+ dp->iq = ialloc(sizeof(IOQ), 0);
+ initq(dp->iq);
+ dp->iq->ptr = dp;
+
+ dp->oq = ialloc(sizeof(IOQ), 0);
+ initq(dp->oq);
+ dp->oq->ptr = dp;
+ dp->oq->puts = duartputs;
+ }
+}
+
+Chan*
+duartattach(char *spec)
+{
+ return devattach('t', spec);
+}
+
+Chan*
+duartclone(Chan *c, Chan *nc)
+{
+ return devclone(c, nc);
+}
+
+int
+duartwalk(Chan *c, char *name)
+{
+ return devwalk(c, name, duartdir, 2*nduartport, devgen);
+}
+
+void
+duartstat(Chan *c, char *dp)
+{
+ switch(STREAMTYPE(c->qid.path)){
+ case Sdataqid:
+ streamstat(c, dp, "tty0");
+ break;
+ default:
+ devstat(c, dp, duartdir, 2*nduartport, devgen);
+ break;
+ }
+}
+
+Chan*
+duartopen(Chan *c, int omode)
+{
+ Duartport *dp;
+
+ switch(STREAMTYPE(c->qid.path)){
+ case Sdataqid:
+ case Sctlqid:
+ dp = &duartport[STREAMID(c->qid.path)];
+ break;
+ default:
+ dp = 0;
+ break;
+ }
+
+ if(dp && dp->nostream)
+ errors("in use");
+
+ if((c->qid.path & CHDIR) == 0)
+ streamopen(c, &duartinfo);
+ return devopen(c, omode, duartdir, 2*nduartport, devgen);
+}
+
+void
+duartcreate(Chan *c, char *name, int omode, ulong perm)
+{
+ errors("only God can create a tty");
+}
+
+void
+duartclose(Chan *c)
+{
+ if(c->stream)
+ streamclose(c);
+}
+
+long
+duartread(Chan *c, void *buf, long n, ulong offset)
+{
+ Duartport *dp;
+
+ if(c->qid.path&CHDIR)
+ return devdirread(c, buf, n, duartdir, 2*nduartport, devgen);
+
+ switch(STREAMTYPE(c->qid.path)){
+ case Sdataqid:
+ return streamread(c, buf, n);
+ case Sctlqid:
+ if(offset)
+ return 0;
+ dp = &duartport[STREAMID(c->qid.path)];
+ qlock(dp);
+ dp->op = Dstate;
+ sleep(&dp->opr, opdone, dp);
+ *(uchar *)buf = dp->val;
+ qunlock(dp);
+ return 1;
+ }
+
+ errors("no such duart type");
+}
+
+long
+duartwrite(Chan *c, void *va, long n, ulong offset)
+{
+ return streamwrite(c, va, n, 0);
+}
+
+void
+duartremove(Chan *c)
+{
+ errors("can't remove a duart");
+}
+
+void
+duartwstat(Chan *c, char *dp)
+{
+ errors("can't write a duart");
+}
+
+int
+duartactive(void)
+{
+ int i;
+
+ for(i = 0; i < nduartport; i++)
+ if(duartport[i].printing)
+ return 1;
+ return 0; }
D power/duart.c => power/duart.c +0 -220
@@ 1,220 0,0 @@
-#include "u.h"
-#include "lib.h"
-#include "mem.h"
-#include "dat.h"
-#include "fns.h"
-#include "io.h"
-
-#define PAD 15 /* registers are well-spaced */
-
-/*
- * Register set for half the duart. There are really two sets.
- */
-struct Duart{
- uchar mr1_2, /* Mode Register Channels 1 & 2 */
- pad0[PAD];
- uchar sr_csr, /* Status Register/Clock Select Register */
- pad1[PAD];
- uchar cmnd, /* Command Register */
- pad2[PAD];
- uchar data, /* RX Holding / TX Holding Register */
- pad3[PAD];
- uchar ipc_acr, /* Input Port Change/Aux. Control Register */
- pad4[PAD];
- uchar is_imr, /* Interrupt Status/Interrupt Mask Register */
- pad5[PAD];
- uchar ctur, /* Counter/Timer Upper Register */
- pad6[PAD];
- uchar ctlr, /* Counter/Timer Lower Register */
- pad7[PAD];
-};
-#define ppcr is_imr /* in the second register set */
-
-#define DBD75 0
-#define DBD110 1
-#define DBD38400 2
-#define DBD150 3
-#define DBD300 4
-#define DBD600 5
-#define DBD1200 6
-#define DBD2000 7
-#define DBD2400 8
-#define DBD4800 9
-#define DBD1800 10
-#define DBD9600 11
-#define DBD19200 12
-
-enum{
- CHAR_ERR =0x00, /* MR1x - Mode Register 1 */
- EVEN_PAR =0x00,
- ODD_PAR =0x04,
- NO_PAR =0x10,
- CBITS8 =0x03,
- CBITS7 =0x02,
- CBITS6 =0x01,
- CBITS5 =0x00,
- NORM_OP =0x00, /* MR2x - Mode Register 2 */
- TWOSTOPB =0x0F,
- ONESTOPB =0x07,
- ENB_RX =0x01, /* CRx - Command Register */
- DIS_RX =0x02,
- ENB_TX =0x04,
- DIS_TX =0x08,
- RESET_MR =0x10,
- RESET_RCV =0x20,
- RESET_TRANS =0x30,
- RESET_ERR =0x40,
- RESET_BCH =0x50,
- STRT_BRK =0x60,
- STOP_BRK =0x70,
- RCV_RDY =0x01, /* SRx - Channel Status Register */
- FIFOFULL =0x02,
- XMT_RDY =0x04,
- XMT_EMT =0x08,
- OVR_ERR =0x10,
- PAR_ERR =0x20,
- FRM_ERR =0x40,
- RCVD_BRK =0x80,
- IM_IPC =0x80, /* IMRx/ISRx - Interrupt Mask/Interrupt Status */
- IM_DBB =0x40,
- IM_RRDYB =0x20,
- IM_XRDYB =0x10,
- IM_CRDY =0x08,
- IM_DBA =0x04,
- IM_RRDYA =0x02,
- IM_XRDYA =0x01,
-};
-
-void
-duartinit(void)
-{
- Duart *duart;
-
- duart = DUARTREG;
-
- duart->cmnd = RESET_RCV|DIS_TX|DIS_RX;
- duart->cmnd = RESET_TRANS;
- duart->cmnd = RESET_ERR;
- duart->cmnd = STOP_BRK;
-
- duart->ipc_acr = 0x80; /* baud-rate set 2 */
- duart->cmnd = RESET_MR;
- duart->mr1_2 = NO_PAR|CBITS8;
- duart->mr1_2 = ONESTOPB;
- duart->sr_csr = (DBD9600<<4)|DBD9600;
- duart->is_imr = IM_RRDYA|IM_XRDYA;
- duart->cmnd = ENB_TX|ENB_RX;
-}
-
-void
-duartreset(void)
-{
- DUARTREG->cmnd = ENB_TX|ENB_RX;
-}
-
-void
-duartintr(void)
-{
- int cause, status, c;
- Duart *duart;
-
- duart = DUARTREG;
- cause = duart->is_imr;
- /*
- * I can guess your interrupt.
- */
- /*
- * Is it 1?
- */
- if(cause & IM_RRDYA){
- /* keyboard input interrupt */
- status = duart->sr_csr;
- c = duart->data;
- if(status & (FRM_ERR|OVR_ERR|PAR_ERR))
- duart->cmnd = RESET_ERR;
- kbdchar(c);
- }
- /*
- * Is it 2?
- */
- if(cause & IM_XRDYA){
- c = conschar();
- if(c == -1)
- duart->cmnd = DIS_TX;
- else
- duart->data = c;
- }
-}
-/*
-int
-duartgetc(void)
-{
- Duart *duart;
- int c;
-
- duart = DUARTREG;
- do; while ((duart->sr_csr & RCV_RDY) == 0);
- c = duart->data&0177;
- consputc(c);
- if(c == '\r'){
- c = '\n';
- consputc(c);
- }
- return c;
-}
-*/
-
-int
-duartputc(int c)
-{
- Duart *duart;
- int i;
-
- duart = DUARTREG;
- if(c == '\n')
- duartputc('\r');
- duart->cmnd = ENB_TX;
- i = 0;
- while((duart->sr_csr&XMT_RDY) == 0)
- if(++i >= 1000000){
- duartinit();
- for(i=0; i<100000; i++)
- ;
- break;
- }
- duart->data = c;
- if(c == '\n')
- for(i=0; i<100000; i++)
- ;
- return c;
-}
-
-void
-duartxmit(int c)
-{
- Duart *duart;
-
- duart = DUARTREG;
- duart->cmnd = ENB_TX;
- duart->data = c;
-}
-
-void
-duartputs(char *s)
-{
- int i;
- while(*s){
- duartputc(*s++);
- }
- for(i=0; i < 1000000; i++)
- ;
-}
-
-void
-iprint(char *s, void *a, void *b, void *c, void *d)
-{
- char buf[1024];
-
- sprint(buf, s, a, b, c, d);
- duartputs(buf);
-}
M power/fns.h => power/fns.h +5 -13
@@ 7,16 7,12 @@ ulong confeval(char*);
void confread(void);
void confprint(void);
void confset(char*);
-int consactive(void);
-int conschar(void);
-void consoff(void);
-int consputc(int);
+void duartspecial(int, IOQ*, IOQ*, int);
+int duartactive(void);
+void duartenable0(void);
void duartinit(void);
void duartintr(void);
-int duartputc(int);
-void duartputs(char*);
-void duartreset(void);
-void duartxmit(int);
+void duartslave(void);
void evenaddr(ulong);
void faultmips(Ureg*, int, int);
ulong fcr31(void);
@@ 28,19 24,16 @@ ulong gettlbvirt(int);
void gotopc(ulong);
void icflush(void *, int);
void ioboardinit(void);
-void kbdchar(int);
void intr(Ureg*);
void lanceintr(void);
void lanceparity(void);
void lancesetup(Lance*);
void launchinit(void);
void launch(int);
-void lights(int);
void newstart(void);
int newtlbpid(Proc*);
void novme(int);
void online(void);
-void printinit(void);
Block* prepend(Block*, int);
void prflush(void);
#define procsetup(p) ((p)->fpstate = FPinit)
@@ 53,12 46,11 @@ void puttlb(ulong, ulong);
void puttlbx(int, ulong, ulong);
int readlog(ulong, char*, ulong);
void restfpregs(FPsave*, ulong);
+#define screenputs
void setvmevec(int, void (*)(int));
void sinit(void);
uchar* smap(int, uchar*);
void sunmap(int, uchar*);
-void syslog(char*, int);
-void sysloginit(void);
void tlbinit(void);
Block* tolance(Block*, int);
void touser(void*);
M power/l.s => power/l.s +0 -3
@@ 160,10 160,8 @@ TEXT gotopc(SB), $8
TEXT puttlb(SB), $4
- JAL splhi(SB)
MOVW 0(FP), R2
MOVW 4(FP), R3
- MOVW R1, 4(SP)
MOVW R2, M(TLBVIRT)
MOVW R3, M(TLBPHYS)
NOOP
@@ 173,7 171,6 @@ TEXT puttlb(SB), $4
BGEZ R4, index
TLBWR
NOOP
- JAL splx(SB)
RET
index:
M power/lock.c => power/lock.c +18 -4
@@ 15,6 15,7 @@
#define SEMPERPG 64 /* hardware semaphores per page */
#define NSEMPG 1024
+#define ULOCKPG 512
struct
{
@@ 22,6 23,7 @@ struct
ulong *nextsem; /* next one to allocate */
int nsem; /* at SEMPERPG, jump to next page */
uchar bmap[NSEMPG]; /* allocation map */
+ int ulockpg; /* count of user lock available */
}semalloc;
Page lkpgheader[NSEMPG];
@@ 32,6 34,7 @@ lockinit(void)
memset(semalloc.bmap, 0, sizeof(semalloc.bmap));
semalloc.bmap[0] = 1;
+ semalloc.ulockpg = ULOCKPG;
semalloc.lock.sbsem = SBSEM;
semalloc.nextsem = SBSEM+1;
semalloc.nsem = 1;
@@ 63,6 66,11 @@ lkpage(Orig *o, ulong va)
int i;
lock(&semalloc.lock);
+ if(--semalloc.ulockpg < 0) {
+ semalloc.ulockpg++;
+ unlock(&semalloc.lock);
+ return 0;
+ }
top = &semalloc.bmap[NSEMPG];
for(p = semalloc.bmap; *p && p < top; p++)
;
@@ 72,23 80,28 @@ lkpage(Orig *o, ulong va)
*p = 1;
i = p-semalloc.bmap;
pg = &lkpgheader[i];
- pg->pa = (ulong)((i*WD2PG) + SBSEM);
+ pg->pa = (ulong)((i*WD2PG) + SBSEM) & ~UNCACHED;
pg->va = va;
pg->o = o;
+ pg->ref = 1;
unlock(&semalloc.lock);
return pg;
}
void
-lkpgfree(ulong *lpa)
+lkpgfree(Page *pg, int dolock)
{
uchar *p;
- p = &semalloc.bmap[(lpa-SBSEM)/WD2PG];
+ lock(&semalloc.lock);
+ p = &semalloc.bmap[((pg->pa|UNCACHED)-(ulong)SBSEM)/BY2PG];
if(!*p)
panic("lkpgfree");
*p = 0;
+
+ semalloc.ulockpg++;
+ unlock(&semalloc.lock);
}
#define PCOFF -9
@@ 171,9 184,10 @@ mklockseg(Seg *s)
Orig *o;
s->proc = u->p;
- o = neworig(LKSEGBASE, 0, OWRPERM|OPURE, 0);
+ o = neworig(LKSEGBASE, 0, OWRPERM|OSHARED, 0);
o->minca = 0;
o->maxca = 0;
+ o->freepg = lkpgfree;
s->o = o;
s->minva = LKSEGBASE;
s->maxva = LKSEGBASE;
M power/main.c => power/main.c +18 -2
@@ 57,6 57,7 @@ main(void)
arginit();
lockinit();
printinit();
+ duartspecial(0, &printq, &kbdq, 9600);
tlbinit();
vecinit();
procinit0();
@@ 83,6 84,7 @@ machinit(void)
memset(m, 0, sizeof(Mach));
m->machno = n;
m->stb = &stlb[n][0];
+ duartinit();
}
void
@@ 370,13 372,13 @@ exit(void)
unlock(&active);
spllo();
print("cpu %d exiting\n", m->machno);
- while(active.machs || consactive())
+ while(active.machs || duartactive())
for(i=0; i<1000; i++)
;
splhi();
for(i=0; i<2000000; i++)
;
- duartreset();
+ duartenable0();
firmware();
}
@@ 819,3 821,17 @@ lanceparity(void)
MODEREG->promenet &= ~4;
MODEREG->promenet |= 4;
}
+
+/*
+ * for the sake of a single devcons.c
+ */
+void
+buzz(int f, int d)
+{
+}
+int
+mouseputc(IOQ *q, int c)
+{
+ return 0;
+}
+
M power/mem.h => power/mem.h +1 -1
@@ 96,7 96,7 @@
#define PTEGLOBL (1<<8)
#define PTEVALID (1<<9)
#define PTEWRITE (1<<10)
-#define PTEUNCACHE (1<<11)
+#define PTEUNCACHED (1<<11)
#define PTERONLY 0
#define PTEPID(n) ((n)<<6)
#define TLBPID(n) (((n)>>6)&0x3F)
M ss/dat.h => ss/dat.h +0 -35
@@ 212,38 212,3 @@ struct
short machs;
short exiting;
}active;
-
-/*
- * character based IO (mouse, keyboard, console screen)
- */
-typedef struct IOQ IOQ;
-typedef struct KIOQ KIOQ;
-#define NQ 4096
-struct IOQ
-{
- Lock;
- uchar buf[NQ];
- uchar *in;
- uchar *out;
- int state;
- Rendez r;
- union{
- void (*puts)(IOQ*, void*, int); /* output */
- int (*putc)(IOQ*, int); /* input */
- };
- void *ptr;
-};
-struct KIOQ
-{
- QLock;
- IOQ;
- int repeat;
- int c;
- int count;
-};
-
-extern IOQ lineq;
-extern IOQ printq;
-extern IOQ mouseq;
-extern KIOQ kbdq;
-
M ss/fns.h => ss/fns.h +1 -31
@@ 59,6 59,7 @@ void restartprint(Alarm*);
void restfpregs(FPsave*);
void screeninit(void);
void screenputc(int);
+void screenputs(char*, int);
void spldone(void);
ulong swap1(ulong*);
void touser(ulong);
@@ 66,34 67,3 @@ void trap(Ureg*);
void trapinit(void);
#define wbflush() /* mips compatibility */
#define waserror() (u->nerrlab++, setlabel(&u->errlab[u->nerrlab-1]))
-
-/*
- * for queues (to go into portfns.h)
- */
-int cangetc(void*);
-int canputc(void*);
-int getc(IOQ*);
-int gets(IOQ*, void*, int);
-void initq(IOQ*);
-int putc(IOQ*, int);
-void puts(IOQ*, void*, int);
-
-/*
- * for the scc (to go into portfns.h)
- */
-void sccintr(void);
-void sccputs(IOQ*, char*, int);
-void sccsetup(void*);
-void sccspecial(int, IOQ*, IOQ*, int);
-
-/*
- * for devcons (to go into portfns.h)
- */
-void kbdclock(void);
-void kbdrepeat(int);
-int kbdputc(IOQ*, int);
-int kprint(char*, ...);
-int mouseputc(IOQ*, int);
-void printinit(void);
-void putstr(char*);
-void putstrn(char*, long);
M ss/mem.h => ss/mem.h +1 -0
@@ 92,6 92,7 @@
#define PTEIO (1<<26)
#define PTEACCESS (1<<25)
#define PTEMODIFY (1<<24)
+#define PTEUNCACHED 0
#define INVALIDPTE 0
#define PPN(pa) ((pa>>12)&0xFFFF)