From cbb4650fd0b62564b623638a03eb5d538ae3cd7c Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Sat, 3 Aug 1991 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 1991-08-03 --- pc/devfloppy.c | 7 ++ pc/devhard.c | 27 +++++++- pc/devuart.c | 22 +++++-- pc/dma.c | 173 +++++++++++++++++++++++++++++++++++++++++++++++++ pc/fns.h | 3 + pc/kbd.c | 77 +++++++++++++++------- pc/main.c | 117 +++++++++++++++++++++++++++++++++ pc/trap.c | 2 +- port/segment.c | 3 +- power/conf.h | 1 + power/dat.h | 1 + power/main.c | 2 + 12 files changed, 399 insertions(+), 36 deletions(-) create mode 100644 pc/dma.c diff --git a/pc/devfloppy.c b/pc/devfloppy.c index 8438a0d1d5292710806aea92df9d8fc58d7e38b2..61522d42824554f2e94c1dfecf692fdbd52f32ef 100644 --- a/pc/devfloppy.c +++ b/pc/devfloppy.c @@ -367,6 +367,7 @@ static void floppykproc(void *a) { Drive *dp; + int disp = 0; waserror(); for(;;){ @@ -378,7 +379,13 @@ floppykproc(void *a) qunlock(dp); } } + disp++; + if(owl(disp&1) < 0) + print("owl failed\n"); + if(mail((disp>>1)&1) < 0) + print("mail failed\n"); tsleep(&floppy.kr, return0, 0, 5*1000); + } } diff --git a/pc/devhard.c b/pc/devhard.c index 96558261a64816768e560a4683c389d9968798b5..f86d0c71808c81dc6ec549e557c800e59cf3ee5c 100644 --- a/pc/devhard.c +++ b/pc/devhard.c @@ -116,6 +116,10 @@ Dirtab harddir[]={ }; #define NHDIR (sizeof(harddir)/sizeof(Dirtab)) +static void hardintr(Ureg*); +static long hardxfer(Drive*, int, void*, long, long); +static long hardident(Drive*); + void hardreset(void) { @@ -213,6 +217,8 @@ hardread(Chan *c, void *a, long n) break; case Qstruct: hardident(dp); + dp->cap = 512 * dp->id->lcyls * dp->id->lheads *dp->id->ls2t; + dp->bytes = 512; if (n < 2*sizeof(ulong)) error(Ebadarg); if (c->offset >= 2*sizeof(ulong)) @@ -257,7 +263,7 @@ hardwrite(Chan *c, void *a, long n) * did an interrupt happen? */ static int -interrupted(Drive *dp) +interrupted(void *a) { return hard.intr; } @@ -265,16 +271,33 @@ interrupted(Drive *dp) /* * get parameters from the drive */ +static long hardident(Drive *dp) { + qlock(&hard); hard.intr = 0; outb(Pdh, dp->dev<<4); outb(Pcmd, Cident); + sleep(&hard.r, interrupted, 0); + insw(Pdata, &hard.id, 512); + qunlock(&hard); } -long +static long hardxfer(Drive *dp, int cmd, void *va, long off, long len) { errors("not implemented"); } +/* + * take/clear a disk interrupt + */ +static void +hardintr(Ureg *ur) +{ + hard.status = inb(Pstatus); + hard.intr = 1; + print("hardintr\n"); + wakeup(&hard.r); +} + diff --git a/pc/devuart.c b/pc/devuart.c index bffa29005bf9eb1adc2630f9eace81638b0cea6f..a914f78bf4030038e6c7e0cb3783f96c03d38ec3 100644 --- a/pc/devuart.c +++ b/pc/devuart.c @@ -37,7 +37,7 @@ enum Loop= (1<<4), /* loop bask */ Lstat= 5, /* line status */ Inready=(1<<0), /* receive buffer full */ - Outbusy=(1<<5), /* output buffer full */ + Outready=(1<<5), /* output buffer full */ Mstat= 6, /* modem status */ Scratch=7, /* scratchpad */ Dlsb= 0, /* divisor lsb */ @@ -88,7 +88,7 @@ uartsetbaud(Uart *up, int rate) { ulong brconst; - brconst = (UartFREQ+8*rate-1)/16*rate; + brconst = (UartFREQ+8*rate-1)/(16*rate); uartwrreg(up, Format, Dra); uartwrreg(up, Dmsb, (brconst>>8) & 0xff); @@ -178,6 +178,7 @@ uartputs(IOQ *cq, char *s, int n) { Uart *up = cq->ptr; int st, ch, x; + int tries; x = splhi(); lock(cq); @@ -187,7 +188,8 @@ uartputs(IOQ *cq, char *s, int n) print("", ch);/**/ if(ch >= 0){ up->printing = 1; - while(uartrdreg(up, Lstat) & Outbusy) + for(tries = 0; tries<10000 && !(uartrdreg(up, Lstat)&Outready); + tries++) ; outb(up->port + Data, ch); } @@ -202,11 +204,13 @@ print("", ch);/**/ void uartintr(Uart *up) { - int s; int ch; IOQ *cq; + int s; - switch(uartrdreg(up, Istat)){ + s = uartrdreg(up, Istat); +print("uartintr %lux\n", s); + switch(s){ case 3: /* * get any input characters @@ -227,10 +231,11 @@ uartintr(Uart *up) /* * send next output character */ - if((s & Outbusy)==0){ + if(uartrdreg(up, Lstat)&Outready){ cq = up->oq; lock(cq); ch = getc(cq); +print("", ch);/**/ if(ch < 0){ up->printing = 0; wakeup(&cq->r); @@ -270,6 +275,7 @@ uartenable(Uart *up) up->iq->ptr = up; up->sticky[Iena] |= Ircv; } + up->sticky[Iena] |= (1<<2) | (1<<3); /* * turn on interrupts @@ -465,7 +471,6 @@ uartkproc(void *a) loop: while ((n = cangetc(cq)) == 0){ -print("uart0 sleeping/n"); sleep(&cq->r, cangetc, cq); } qlock(up); @@ -506,6 +511,9 @@ uartreset(void) { Uart *up; + if(serial(0) < 0) + print("can't turn on power\n"); + uartsetup(); for(up = uart; up < &uart[2]; up++){ if(up->nostream) diff --git a/pc/dma.c b/pc/dma.c new file mode 100644 index 0000000000000000000000000000000000000000..4c217df7511bf98c9daf13236f980ec2bbe56eb3 --- /dev/null +++ b/pc/dma.c @@ -0,0 +1,173 @@ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" + +/* + * headland chip set for the safari. + */ +typedef struct DMAport DMAport; +typedef struct DMA DMA; +typedef struct DMAxfer DMAxfer; + +enum +{ + /* + * the byte registers for DMA0 are all one byte apart + */ + Dma0= 0x00, + Dma0status= Dma0+0x8, /* status port */ + Dma0reset= Dma0+0xD, /* reset port */ + + /* + * the byte registers for DMA1 are all two bytes apart (why?) + */ + Dma1= 0xC0, + Dma1status= Dma1+2*0x8, /* status port */ + Dma1reset= Dma1+2*0xD, /* reset port */ +}; + +/* + * state of a dma transfer + */ +struct DMAxfer +{ + Page *pg; /* page used by dma */ + void *va; /* virtual address destination/src */ + long len; /* bytes to be transferred */ + int isread; +}; + +/* + * the dma controllers. the first half of this structure specifies + * the I/O ports used by the DMA controllers. + */ +struct DMAport +{ + uchar addr[4]; /* current address (4 channels) */ + uchar count[4]; /* current count (4 channels) */ + uchar page[4]; /* page registers (4 channels) */ + uchar cmd; /* command status register */ + uchar req; /* request registers */ + uchar sbm; /* single bit mask register */ + uchar mode; /* mode register */ + uchar cbp; /* clear byte pointer */ + uchar mc; /* master clear */ + uchar cmask; /* clear mask register */ + uchar wam; /* write all mask register bit */ + + Lock; +}; + +struct DMA +{ + DMAport; + Lock; + DMAxfer x[4]; +}; + +DMA dma[2] = { + { 0x00, 0x02, 0x04, 0x06, + 0x01, 0x03, 0x05, 0x07, + 0x87, 0x83, 0x81, 0x82, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }, + { 0xc0, 0xc6, 0xca, 0xce, + 0xc4, 0xc8, 0xcc, 0xcf, + 0x80, 0x8b, 0x89, 0x8a, + 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde }, +}; + +/* + * setup a dma transfer. if the destination is not in kernel + * memory, allocate a page for the transfer. + * + * we assume BIOS has set up the command register before we + * are booted. + * + * return the updated transfer length (we can't transfer across 64k + * boundaries) + */ +long +dmasetup(int chan, void *va, long len, int isread) +{ + DMA *dp; + DMAxfer *xp; + ulong pa; + uchar mode; + + dp = &dma[(chan>>2)&1]; + chan = chan & 3; + xp = &dp->x[chan]; + + /* + * if this isn't kernel memory (or crossing 64k boundary), + * allocate a page for the DMA. + */ + pa = ((ulong)va) & ~KZERO; + if(!isphys(va) || (pa&0xFFFF0000)!=((pa+len)&0xFFFF0000)){ + xp->pg = newpage(1, 0, 0); + if(len > BY2PG) + len = BY2PG; + if(!isread) + memmove((void*)(KZERO|xp->pg->pa), va, len); + xp->va = va; + xp->len = len; + xp->isread = isread; + pa = xp->pg->pa; + } + + /* + * this setup must be atomic + */ + lock(dp); + outb(dp->cbp, 0); /* set count & address to their first byte */ + mode = (isread ? 0x44 : 0x48) | chan; + outb(dp->mode, mode); /* single mode dma (give CPU a chance at mem) */ + outb(dp->addr[chan], pa); /* set address */ + outb(dp->addr[chan], pa>>8); + outb(dp->page[chan], pa>>16); + outb(dp->count[chan], len-1); /* set count */ + outb(dp->count[chan], (len-1)>>8); + outb(dp->sbm, chan); /* enable the channel */ + unlock(dp); + + return len; +} + +/* + * this must be called after a dma has been completed. + * + * if a page has been allocated for the dma, + * copy the data into the actual destination + * and free the page. + */ +void +dmaend(int chan) +{ + DMA *dp; + DMAxfer *xp; + ulong addr; + uchar mode; + + dp = &dma[(chan>>2)&1]; + chan = chan & 3; + + /* + * disable the channel + */ + lock(dp); + outb(dp->sbm, 4|chan); + unlock(dp); + + xp = &dp->x[chan]; + if(xp->pg == 0) + return; + + /* + * copy out of temporary page + */ + memmove(xp->va, (void*)(KZERO|xp->pg->pa), xp->len); + putpage(xp->pg); + xp->pg = 0; +} diff --git a/pc/fns.h b/pc/fns.h index b552fef9c82b260abf51a68acc23de16460a03e4..961da73598662924fba147c3ef89df592f308883 100644 --- a/pc/fns.h +++ b/pc/fns.h @@ -16,6 +16,8 @@ void fprestore(FPsave*); ulong getcr2(void); void idle(void); int inb(int); +int inss(int, void*, int); +int outss(int, void*, int); void kbdinit(void); void kbdintr(Ureg*); void mmuinit(void); @@ -31,6 +33,7 @@ void puttr(ulong); void screeninit(void); void screenputc(int); void screenputs(char*, int); +int serial(int); void setvec(int, void (*)(Ureg*)); void systrap(void); void touser(void); diff --git a/pc/kbd.c b/pc/kbd.c index d44d5918cb550f7e1c21be41405f133047adaf7a..9d44459c6e14923c955f083950035babd5538c21 100644 --- a/pc/kbd.c +++ b/pc/kbd.c @@ -240,35 +240,64 @@ latin1(int k1, int k2) return 0; } -static void -mousecmd(int cmd, int arg) +/* + * wait for output no longer busy + */ +static int +outready(void) +{ + int tries; + + for(tries = 0; (inb(Status) & Outbusy); tries++) + if(tries > 1000) + return -1; + return 0; +} + +/* + * wait for input + */ +static int +inready(void) +{ + int tries; + + for(tries = 0; !(inb(Status) & Inready); tries++) + if(tries > 1000) + return -1; + return 0; +} + +/* + * send a command to the mouse + */ +static int +mousecmd(int cmd) { unsigned int c; + int tries; - do { - while(inb(Status) & Outbusy) - ; + for(tries=0; tries < 10; tries++){ + if(outready() < 0) + return -1; outb(Cmd, 0xD4); - while(inb(Status) & Outbusy) - ; + if(outready() < 0) + return -1; outb(Data, cmd); - if(arg >= 0){ - while(inb(Status) & Outbusy) - ; - outb(Data, arg); - } - while(!(inb(Status) & Inready)) - ; + if(inready() < 0) + return -1; c = inb(Data); } while(c == 0xFE); if(c != 0xFA) - print("mouse command returns bad status %lux", c); + return -1; + return 0; } void kbdinit(void) { int c, s; + int tries; initq(&kbdq); setvec(Kbdvec, kbdintr); @@ -282,19 +311,17 @@ kbdinit(void) /* enable kbd/mouse xfers and interrupts */ outb(Cmd, 0x60); - while(inb(Status) & Outbusy) - ; + if(outready() < 0) + print("kbd init failed\n"); outb(Data, 0x47); - while(inb(Status) & Outbusy) - ; + if(outready() < 0) + print("kbd init failed\n"); outb(Cmd, 0xA8); - /* make mouse streaming (and enabled) */ - mousecmd(0xEA, -1); - mousecmd(0xF4, -1); - - /* resolution */ -/* mousecmd(0xE8, 0x03); /**/ + /* make mouse streaming, enabled */ + if(mousecmd(0xEA) < 0 + || mousecmd(0xF4) < 0) + print("can't initialize mouse\n"); } /* diff --git a/pc/main.c b/pc/main.c index 1b3dcb5b157574620fe4ee65aa48986a92c7534d..4527eb17477b31682ab7b4dfea852d9a9ddf2641 100644 --- a/pc/main.c +++ b/pc/main.c @@ -265,3 +265,120 @@ void lights(int val) { } + + +/* + * special stuff for 80c51 power management and headland system controller + */ +enum +{ + /* + * system control port + */ + Head= 0x92, /* control port */ + Reset= (1<<0), /* reset the 386 */ + A20ena= (1<<1), /* enable address line 20 */ + + /* + * power management unit ports + */ + Pmudata= 0x198, + + Pmucsr= 0x199, + Busy= 0x1, +}; + +/* + * enable address bit 20 + */ +void +a20enable(void) +{ + outb(Head, A20ena); +} + +/* + * reset the chip + */ +void +exit(void) +{ + int i; + + u = 0; + print("exiting\n"); + outb(Head, Reset); +} + +/* + * return when pmu ready + */ +static int +pmuready(void) +{ + int tries; + + for(tries = 0; (inb(Pmucsr) & Busy); tries++) + if(tries > 1000) + return -1; + return 0; +} + +/* + * return when pmu busy + */ +static int +pmubusy(void) +{ + int tries; + + for(tries = 0; !(inb(Pmucsr) & Busy); tries++) + if(tries > 1000) + return -1; + return 0; +} + +/* + * set a bit in the PMU + */ +int +pmuwrbit(int index, int bit, int pos) +{ + outb(Pmucsr, 0x02); /* next is command request */ + if(pmuready() < 0) + return -1; + outb(Pmudata, (2<<4) | index); /* send write bit command */ + outb(Pmucsr, 0x01); /* send available */ + if(pmubusy() < 0) + return -1; + outb(Pmucsr, 0x01); /* next is data */ + if(pmuready() < 0) + return -1; + outb(Pmudata, (bit<<3) | pos); /* send bit to write */ + outb(Pmucsr, 0x01); /* send available */ + if(pmubusy() < 0) + return -1; +} + +/* + * control power to the serial line + * onoff == 0 means turn power on + * onoff == 1 means off + */ +int +serial(int onoff) +{ + return pmuwrbit(1, onoff, 6); +} + +int +owl(int onoff) +{ + return pmuwrbit(0, onoff, 4); +} + +int +mail(int onoff) +{ + return pmuwrbit(0, onoff, 1); +} diff --git a/pc/trap.c b/pc/trap.c index 1d52aec7f8dc7a1827eaa840c89182548af6eaba..20e2dd561936e094eb930d0ba04cf1d5f8b4e8bc 100644 --- a/pc/trap.c +++ b/pc/trap.c @@ -35,7 +35,7 @@ enum }; int int0mask = 0xff; /* interrupts enabled for first 8259 */ -int int1mask = 0xff; /* interrupts enabled for second 8259 */ +int int1mask = 0xff; /* interrupts enabled for second 8259 */ /* * trap/interrupt gates diff --git a/port/segment.c b/port/segment.c index 6f7c41319dd3bcbf135849c44dce10799518d36b..67a8472243d54272b795108e80c4875f261a1db7 100644 --- a/port/segment.c +++ b/port/segment.c @@ -438,7 +438,8 @@ segattach(Proc *p, ulong attr, char *name, ulong va, ulong len) ns = u->p->seg[i]; if(ns == 0) continue; - if(newtop >= ns->base && newtop < ns->top) + if((newtop > ns->base && newtop <= ns->top) || + (va >= ns->base && va < ns->top)) errors("segments overlap"); } diff --git a/power/conf.h b/power/conf.h index 278d4ba91a25b89234330cfe4703776dfa23a48c..62da05ae8d366f05e2afca503c3a94a0bd9ecbd9 100644 --- a/power/conf.h +++ b/power/conf.h @@ -3,6 +3,7 @@ Conftab conftab[] = { {"nproc", &conf.nproc }, {"npgrp", &conf.npgrp }, {"npage0", &conf.npage0 }, + {"npage1", &conf.npage1 }, {"npage", &conf.npage }, {"nseg", &conf.nseg }, {"nimage", &conf.nimage }, diff --git a/power/dat.h b/power/dat.h index 8e26790eea52360d2e3aca4ebed752ab7efdd942..0862fd0e931183854203668a911f9cdc33f005b4 100644 --- a/power/dat.h +++ b/power/dat.h @@ -40,6 +40,7 @@ struct Conf ulong nproc; /* processes */ ulong npgrp; /* process groups */ ulong npage0; /* total physical pages of memory */ + ulong npage1; /* total physical pages of memory */ ulong npage; /* total physical pages of memory */ ulong nseg; /* number of segments */ ulong nimage; /* number of page cache image headers */ diff --git a/power/main.c b/power/main.c index 6dbaf98caed805d26d0648c2e680cd6108ad5bf3..126e27069afdad2aafd9b9f0eefeb018a74a5818 100644 --- a/power/main.c +++ b/power/main.c @@ -539,6 +539,8 @@ confinit(void) conf.npage0 = i*1024/4; conf.base0 = 0; conf.npage = conf.npage0; + conf.npage1 = 0; + conf.base1 = 0; conf.maxialloc = (128*1024*1024-256*1024-BY2PG); /*