From 014857cc7cfd364411f471b44f77b62e56810317 Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Fri, 10 Sep 1999 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 1999-09-10 --- ip/devip.c | 2 +- ip/ip.h | 2 +- ip/udp.c | 86 +++++++++----- pc/vgaclgd546x.c | 290 ++++++++++++++++++++++++++++++++++++++++++++++ port/devsdp.c | 295 ++++++++++++++++++++++++++++------------------- 5 files changed, 526 insertions(+), 149 deletions(-) create mode 100644 pc/vgaclgd546x.c diff --git a/ip/devip.c b/ip/devip.c index ff772ac3d940d2790864d3e495c02a3b26043a02..7166ec51e941987a6fa572c108d67ebb496ae1b0 100644 --- a/ip/devip.c +++ b/ip/devip.c @@ -462,7 +462,7 @@ ipwstat(Chan*, char*) error(Eperm); } -static void +void closeconv(Conv *cv) { Conv *nc; diff --git a/ip/ip.h b/ip/ip.h index f5eb7d01726c06c9e7d91c8c6d253ae209fefb89..0314ea374420fc28afd58282e2533c58eaa63b1b 100644 --- a/ip/ip.h +++ b/ip/ip.h @@ -278,7 +278,7 @@ Proto* Fsrcvpcolx(Fs*, uchar); char* Fsstdconnect(Conv*, char**, int); char* Fsstdannounce(Conv*, char**, int); char* Fsstdbind(Conv*, char**, int); - +void closeconv(Conv*); /* * logging */ diff --git a/ip/udp.c b/ip/udp.c index 754ad9e97427aea39d48460ce725ac38451c23b0..d7eff2ae775dffcedee4b0b6113cbd2cda9db46e 100644 --- a/ip/udp.c +++ b/ip/udp.c @@ -119,6 +119,7 @@ udpclose(Conv *c) { Udpcb *ucb; + c->state = 0; qclose(c->rq); qclose(c->wq); qclose(c->eq); @@ -234,7 +235,7 @@ udpiput(Proto *udp, uchar *ia, Block *bp) { int len, olen, ottl; Udphdr *uh; - Conv *c, **p, *gc; + Conv *c, **p, *spec, *gen; Udpcb *ucb; uchar raddr[IPaddrlen], laddr[IPaddrlen]; ushort rport, lport; @@ -273,11 +274,9 @@ udpiput(Proto *udp, uchar *ia, Block *bp) qlock(udp); /* - * Look for a conversation structure for this port. One - * with headers off wins over one with headers on, i.e., - * specific wins over generic. + * Look for a conversation structure for this packet */ - gc = c = nil; + spec = gen = c = nil; for(p = udp->conv; *p; p++) { c = *p; if(c->inuse == 0) @@ -285,23 +284,41 @@ udpiput(Proto *udp, uchar *ia, Block *bp) if(c->lport == lport){ ucb = (Udpcb*)c->ptcl; - /* with headers turned on, descriminate only on local port */ - if(ucb->headers && gc == nil){ - gc = c; - continue; + switch(c->state){ + case Announced: + /* headers + Announced is special behaviour */ + if(ucb->headers) + goto found; + spec = c; + break; + + case Connected: + /* exact match */ + if(c->rport == rport) + if(ipcmp(c->raddr, raddr) == 0 || ipisbm(c->raddr)) + goto found; } - /* otherwise discriminate on lport, rport, and raddr */ - if(c->rport == 0 || c->rport == rport) - if(ipisbm(c->raddr) || ipcmp(c->raddr, IPnoaddr) == 0 - || ipcmp(c->raddr, raddr) == 0) - break; + } else if(c->lport == 0) { + /* generic listen for all udp ports */ + if(c->state == Announced) + gen = c; } } +found: if(*p == nil){ - if(gc != nil) - c = gc; - else { + if(spec != nil) + gen = spec; + if(gen != nil){ + if(ipforme(f, laddr) != Runi) + v4tov6(laddr, ia); + c = Fsnewcall(gen, raddr, rport, laddr, lport); + if(c == nil){ + freeblist(bp); + return; + } + c->state = Connected; + } else { upriv->ustats.udpNoPorts++; qunlock(udp); netlog(f, Logudp, "udp: no conv %I!%d -> %I!%d\n", raddr, rport, @@ -357,21 +374,8 @@ udpiput(Proto *udp, uchar *ia, Block *bp) hnputs(bp->rp + 2*IPv4addrlen, rport); hnputs(bp->rp + 2*IPv4addrlen + 2, lport); break; - default: - /* connection oriented udp */ - if(ipcmp(c->raddr, IPnoaddr) == 0){ - /* save the src address in the conversation */ - ipmove(c->raddr, raddr); - c->rport = rport; - - /* reply with the same ip address (if not broadcast) */ - if(ipforme(f, laddr) == Runi) - ipmove(c->laddr, laddr); - else - v4tov6(c->laddr, ia); - } - break; } + if(bp->next) bp = concatblock(bp); @@ -388,6 +392,22 @@ udpiput(Proto *udp, uchar *ia, Block *bp) } +/* close any incoming calls waiting on this conversation */ +void +udpcloseincalls(Conv *c) +{ + Conv *nc; + + qlock(c); + + for(nc = c->incall; nc; nc = c->incall){ + c->incall = nc->next; + closeconv(nc); + } + + qunlock(c); +} + char* udpctl(Conv *c, char **f, int n) { @@ -397,9 +417,13 @@ udpctl(Conv *c, char **f, int n) if(n == 1){ if(strcmp(f[0], "headers4") == 0){ ucb->headers = 4; + /* close any calls that got in twixt announce and headers */ + udpcloseincalls(c); return nil; } else if(strcmp(f[0], "headers") == 0){ ucb->headers = 6; + /* close any calls that got in twixt announce and headers */ + udpcloseincalls(c); return nil; } } diff --git a/pc/vgaclgd546x.c b/pc/vgaclgd546x.c new file mode 100644 index 0000000000000000000000000000000000000000..cca156235a7972b5614b08cca907d10dfb60dab9 --- /dev/null +++ b/pc/vgaclgd546x.c @@ -0,0 +1,290 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" +#include "../port/error.h" + +#define Image IMAGE +#include +#include +#include +#include "screen.h" + +typedef struct { + ushort x; + ushort y; + ushort preset; + ushort enable; + ushort addr; +} Cursor546x; + +enum { + PaletteState = 0xB0, + CursorMMIO = 0xE0, +}; + +static ulong +clgd546xlinear(VGAscr* scr, int* size, int* align) +{ + ulong aperture, oaperture; + int oapsize, wasupamem; + Pcidev *p; + + oaperture = scr->aperture; + oapsize = scr->apsize; + wasupamem = scr->isupamem; + + aperture = 0; + if(p = pcimatch(nil, 0x1013, 0)){ + switch(p->did){ + case 0xD0: + case 0xD4: + case 0xD6: + aperture = p->mem[0].bar & ~0x0F; + *size = p->mem[0].size; + break; + default: + break; + } + } + + if(wasupamem){ + if(oaperture == aperture) + return oaperture; + upafree(oaperture, oapsize); + } + scr->isupamem = 0; + + aperture = upamalloc(aperture, *size, *align); + if(aperture == 0){ + if(wasupamem && upamalloc(oaperture, oapsize, 0)){ + aperture = oaperture; + scr->isupamem = 1; + } + else + scr->isupamem = 0; + } + else + scr->isupamem = 1; + + return aperture; +} +static void +clgd546xenable(VGAscr* scr) +{ + Pcidev *p; + Physseg seg; + int size, align; + ulong aperture; + + /* + * Only once, can't be disabled for now. + * scr->io holds the virtual address of + * the MMIO registers. + */ + if(scr->io) + return; + if(p = pcimatch(nil, 0x1013, 0)){ + switch(p->did){ + case 0xD0: + case 0xD4: + case 0xD6: + break; + default: + return; + } + } + else + return; + scr->io = upamalloc(p->mem[1].bar & ~0x0F, p->mem[1].size, 0); + if(scr->io == 0) + return; + + memset(&seg, 0, sizeof(seg)); + seg.attr = SG_PHYSICAL; + seg.name = smalloc(NAMELEN); + snprint(seg.name, NAMELEN, "clgd546xmmio"); + seg.pa = scr->io; + seg.size = p->mem[1].size; + addphysseg(&seg); + + scr->io = (ulong)KADDR(scr->io); + + size = p->mem[0].size; + align = 0; + aperture = clgd546xlinear(scr, &size, &align); + if(aperture) { + scr->aperture = aperture; + scr->apsize = size; + memset(&seg, 0, sizeof(seg)); + seg.attr = SG_PHYSICAL; + seg.name = smalloc(NAMELEN); + snprint(seg.name, NAMELEN, "clgd546xscreen"); + seg.pa = aperture; + seg.size = size; + addphysseg(&seg); + } +} + +static void +clgd546xcurdisable(VGAscr* scr) +{ + Cursor546x *cursor546x; + + if(scr->io == 0) + return; + cursor546x = (Cursor546x*)(scr->io+CursorMMIO); + cursor546x->enable = 0; +} + +static void +clgd546xcurload(VGAscr* scr, Cursor* curs) +{ + int c, i, m, y; + uchar *p; + Cursor546x *cursor546x; + + if(scr->io == 0) + return; + cursor546x = (Cursor546x*)(scr->io+CursorMMIO); + + /* + * Disable the cursor then change only the bits + * that need it. + */ + cursor546x->enable = 0; + p = (uchar*)(scr->aperture + scr->storage); + for(y = 0; y < 16; y++){ + c = curs->set[2*y]; + m = 0; + for(i = 0; i < 8; i++){ + if(c & (1<<(7-i))) + m |= 1<set[2*y + 1]; + m = 0; + for(i = 0; i < 8; i++){ + if(c & (1<<(7-i))) + m |= 1<set[2*y]|curs->clr[2*y]; + m = 0; + for(i = 0; i < 8; i++){ + if(c & (1<<(7-i))) + m |= 1<set[2*y + 1]|curs->clr[2*y + 1]; + m = 0; + for(i = 0; i < 8; i++){ + if(c & (1<<(7-i))) + m |= 1<offset = curs->offset; + cursor546x->enable = 1; +} + +static int +clgd546xcurmove(VGAscr* scr, Point p) +{ + int x, xo, y, yo; + Cursor546x *cursor546x; + + if(scr->io == 0) + return 1; + cursor546x = (Cursor546x*)(scr->io+CursorMMIO); + + if((x = p.x+scr->offset.x) < 0){ + xo = -x; + x = 0; + } + else + xo = 0; + if((y = p.y+scr->offset.y) < 0){ + yo = -y; + y = 0; + } + else + yo = 0; + + cursor546x->preset = (xo<<8)|yo; + cursor546x->x = x; + cursor546x->y = y; + + return 0; +} + +static void +clgd546xcurenable(VGAscr* scr) +{ + uchar *p; + Cursor546x *cursor546x; + + clgd546xenable(scr); + if(scr->io == 0) + return; + cursor546x = (Cursor546x*)(scr->io+CursorMMIO); + + /* + * Cursor colours. + * Can't call setcolor here as cursor is already locked. + */ + p = (uchar*)(scr->io+PaletteState); + *p |= 0x08; + vgao(PaddrW, 0x00); + vgao(Pdata, Pwhite); + vgao(Pdata, Pwhite); + vgao(Pdata, Pwhite); + vgao(PaddrW, 0x0F); + vgao(Pdata, Pblack); + vgao(Pdata, Pblack); + vgao(Pdata, Pblack); + *p &= ~0x08; + + /* + * Find a place for the cursor data in display memory. + * 2 cursor images might be needed, 1KB each so use the last + * 2KB of the framebuffer and initialise them to be + * transparent. + */ + scr->storage = ((vgaxi(Seqx, 0x14) & 0x07)+1)*1024*1022; + cursor546x->addr = (scr->storage>>10)<<2; + memset((uchar*)(scr->aperture + scr->storage), 0, 2*64*16); + + /* + * Load, locate and enable the 64x64 cursor. + */ + clgd546xcurload(scr, &arrow); + clgd546xcurmove(scr, ZP); + cursor546x->enable = 1; +} + +VGAdev vgaclgd546xdev = { + "clgd546x", + + clgd546xenable, + nil, + nil, + clgd546xlinear, +}; + +VGAcur vgaclgd546xcur = { + "clgd546xhwgc", + + clgd546xcurenable, + clgd546xcurdisable, + clgd546xcurload, + clgd546xcurmove, +}; diff --git a/port/devsdp.c b/port/devsdp.c index 8799c9f196a18911e45bda34606b0d268f96a449..2721562b20e1ebb00b44d390f0cade11b3af0de8 100644 --- a/port/devsdp.c +++ b/port/devsdp.c @@ -74,7 +74,8 @@ enum { CDial, CAccept, COpen, - CClosing, + CLocalClose, + CRemoteClose, CClosed, }; @@ -86,7 +87,7 @@ struct Conv { int state; int dataopen; - + int reader; // reader proc has been started ulong timeout; int retries; @@ -95,9 +96,11 @@ struct Conv { ulong dialid; ulong acceptid; + QLock readlk; // protects readproc Proc *readproc; - QLock readlk; + Chan *chan; // packet channel + char *channame; char owner[NAMELEN]; /* protections */ int perm; @@ -131,8 +134,8 @@ enum { enum { ConOpenRequest, ConOpenAck, + ConOpenAckAck, ConClose, - ConCloseAck, ConReset, }; @@ -186,7 +189,8 @@ static char *convstatename[] = { [CDial] "Dial", [CAccept] "Accept", [COpen] "Open", - [CClosing] "Closing", + [CLocalClose] "LocalClose", + [CRemoteClose] "RemoteClose", [CClosed] "Closed", }; @@ -203,6 +207,7 @@ static Block *readcontrol(Conv *c, int n); static Block *readdata(Conv *c, int n); static void convoput(Conv *c, int type, Block *b); static void convoput2(Conv *c, int op, ulong dialid, ulong acceptid); +static void convreader(void *a); static void @@ -328,8 +333,12 @@ sdpopen(Chan* ch, int omode) if(strcmp(up->user, c->owner) != 0 || (perm & c->perm) != perm) error(Eperm); c->ref++; - if(TYPE(ch->qid) == Qdata) + if(TYPE(ch->qid) == Qdata) { + if(c->dataopen == 0) + if(c->readproc != nil) + postnote(c->readproc, 1, "interrupt", 0); c->dataopen++; + } qunlock(c); poperror(); break; @@ -377,10 +386,10 @@ print("close c->ref = %d\n", c->ref); break; case CAccept: case COpen: - convsetstate(c, CClosing); - break; - case CClosing: + convsetstate(c, CLocalClose); break; + case CLocalClose: + panic("local close already happened"); } } qunlock(c); @@ -474,20 +483,22 @@ print("Qctl write : conv->id = %d\n", c->id); error("short write"); arg0 = cb->f[0]; print("cmd = %s\n", arg0); - if(strcmp(arg0, "chan") == 0) { + if(strcmp(arg0, "accept") == 0) { if(cb->nf != 2) - error("usage: chan file"); + error("usage: accect file"); if(c->chan != nil) - error("chan already set"); + error("already connected"); c->chan = namec(cb->f[1], Aopen, ORDWR, 0); - } else if(strcmp(arg0, "accept") == 0) { - if(cb->nf != 2) - error("usage: accect id"); - c->dialid = atoi(cb->f[1]); - convsetstate(c, CAccept); + c->channame = malloc(strlen(cb->f[1])+1); + strcpy(c->channame, cb->f[1]); } else if(strcmp(arg0, "dial") == 0) { - if(cb->nf != 1) - error("usage: dial"); + if(cb->nf != 2) + error("usage: accect file"); + if(c->chan != nil) + error("already connected"); + c->chan = namec(cb->f[1], Aopen, ORDWR, 0); + c->channame = malloc(strlen(cb->f[1])+1); + strcpy(c->channame, cb->f[1]); convsetstate(c, CDial); } else if(strcmp(arg0, "drop") == 0) { if(cb->nf != 2) @@ -584,7 +595,7 @@ sdpclone(Sdp *sdp) break; } if(canqlock(c)){ - if(c->state == CClosed) + if(c->state == CClosed && c->reader == 0) break; qunlock(c); } @@ -597,7 +608,10 @@ sdpclone(Sdp *sdp) c->ref++; c->state = CInit; - + if(!waserror()) { + kproc("convreader", convreader, c); + c->reader = 1; + } strncpy(c->owner, up->user, sizeof(c->owner)); c->perm = 0660; qunlock(c); @@ -647,11 +661,13 @@ print("convtimer: %s\n", convstatename[c->state]); case CAccept: if(convretry(c)) convoput2(c, ConOpenAck, c->dialid, c->acceptid); + else + convoput2(c, ConReset, c->dialid, c->acceptid); break; case COpen: // check for control packet and keepalive break; - case CClosing: + case CLocalClose: if(convretry(c)) convoput2(c, ConClose, c->dialid, c->acceptid); break; @@ -730,15 +746,18 @@ print("convsetstate %s -> %s\n", convstatename[c->state], convstatename[state]); assert(c->state == CDial || c->state == CAccept); if(c->state == CDial) { convretryinit(c); - convoput2(c, ConOpenAck, c->dialid, c->acceptid); + convoput2(c, ConOpenAckAck, c->dialid, c->acceptid); } // setup initial key and auth method break; - case CClosing: - assert(c->state == COpen); + case CLocalClose: + assert(c->state == CAccept || c->state == COpen); convretryinit(c); convoput2(c, ConClose, c->dialid, c->acceptid); break; + case CRemoteClose: + convoput2(c, ConReset, c->dialid, c->acceptid); + break; case CClosed: if(c->readproc) postnote(c->readproc, 1, "interrupt", 0); @@ -748,6 +767,10 @@ print("convsetstate %s -> %s\n", convstatename[c->state], convstatename[state]); cclose(c->chan); c->chan = nil; } + if(c->channame) { + free(c->channame); + c->channame = nil; + } strcpy(c->owner, "network"); c->perm = 0660; c->dialid = 0; @@ -778,34 +801,6 @@ onewaycleanup(OneWay *ow) } -static Block * -convreadblock(Conv *c, int n) -{ - Block *b; - - qlock(&c->readlk); - if(waserror()) { - c->readproc = nil; - qunlock(&c->readlk); - nexterror(); - } - qlock(c); - if(c->state == CClosed) { - qunlock(c); - poperror(); - qunlock(&c->readlk); - return 0; - } - c->readproc = up; - qunlock(c); - - b = devtab[c->chan->type]->bread(c->chan, n, 0); - c->readproc = nil; - poperror(); - qunlock(&c->readlk); - - return b; -} // assume we hold lock for c @@ -853,8 +848,6 @@ conviput(Conv *c, Block *b, int control) c->in.controlseq = cseq; b->rp += 4; - if(control) - return b; c->in.controlpkt = b; wakeup(&c->in.controlready); return nil; @@ -895,63 +888,96 @@ conviput2(Conv *c, Block *b) dialid = nhgetl(con->dialid); acceptid = nhgetl(con->acceptid); -print("conviput2: %d %uld %uld\n", con->op, dialid, acceptid); + switch(c->state) { + default: + panic("unknown state: %d", c->state); + case CInit: + break; + case CDial: + if(dialid != c->dialid) + goto Reset; + break; + case CAccept: + case COpen: + case CLocalClose: + case CRemoteClose: + if(dialid != c->dialid || acceptid != c->acceptid) + goto Reset; + break; + case CClosed: + goto Reset; + } + + +print("conviput2: %s: %d %uld %uld\n", convstatename[c->state], con->op, dialid, acceptid); switch(con->op) { case ConOpenRequest: switch(c->state) { - default: - convoput2(c, ConReset, dialid, acceptid); - break; case CInit: c->dialid = dialid; convsetstate(c, CAccept); - break; + return; case CAccept: case COpen: - if(dialid != c->dialid || acceptid != c->acceptid) - convoput2(c, ConReset, dialid, acceptid); - break; + // duplicate ConOpenRequest that we ignore + return; } break; case ConOpenAck: switch(c->state) { case CDial: - if(dialid != c->dialid) { - convoput2(c, ConReset, dialid, acceptid); - break; - } c->acceptid = acceptid; convsetstate(c, COpen); - break; + return; + case COpen: + // duplicate that we have to ack + convoput2(c, ConOpenAckAck, acceptid, dialid); + return; + } + break; + case ConOpenAckAck: + switch(c->state) { case CAccept: - if(dialid != c->dialid || acceptid != c->acceptid) { - convoput2(c, ConReset, dialid, acceptid); - break; - } convsetstate(c, COpen); + return; + case COpen: + // duplicate that we ignore + return; } break; case ConClose: - convoput2(c, ConCloseAck, dialid, acceptid); - // fall though - case ConReset: + convoput2(c, ConReset, dialid, acceptid); switch(c->state) { + case CInit: case CDial: - if(dialid == c->dialid) - convsetstate(c, CClosed); - break; case CAccept: + case CLocalClose: + convsetstate(c, CClosed); + return; case COpen: - case CClosing: - if(dialid == c->dialid && acceptid == c->acceptid) - convsetstate(c, CClosed); - break; + convsetstate(c, CRemoteClose); + return; + case CRemoteClose: + return; } - case ConCloseAck: - if(c->state == CClosing && dialid == c->dialid && acceptid == c->acceptid) + return; + case ConReset: + switch(c->state) { + case CInit: + case CDial: + case CAccept: + case COpen: + case CLocalClose: convsetstate(c, CClosed); - break; + return; + case CRemoteClose: + return; + } + return; } +Reset: + // invalid connection message - reset to sender + convoput2(c, ConReset, dialid, acceptid); } // assume hold conv lock @@ -1003,12 +1029,45 @@ print("chan = nil\n"); devtab[c->chan->type]->write(c->chan, &con, sizeof(con), 0); } +static Block * +convreadblock(Conv *c, int n) +{ + Block *b; + Chan *ch = nil; + + qlock(&c->readlk); + if(waserror()) { + c->readproc = nil; + if(ch) + cclose(ch); + qunlock(&c->readlk); + nexterror(); + } + qlock(c); + if(c->state == CClosed) { + qunlock(c); + error("closed"); + } + c->readproc = up; + ch = c->chan; + incref(ch); + qunlock(c); + + b = devtab[ch->type]->bread(ch, n, 0); + c->readproc = nil; + cclose(ch); + poperror(); + qunlock(&c->readlk); + + return b; +} + static int readready(void *a) { Conv *c = a; - return (c->state == CClosed) || c->in.controlpkt != nil || c->dataopen == 0; + return (c->state == CClosed) || c->in.controlpkt != nil; } static Block * @@ -1016,9 +1075,10 @@ readcontrol(Conv *c, int n) { Block *b; + USED(n); for(;;) { qlock(c); - if(c->state == CClosed || c->state == CInit) { + if(c->state == CInit || c->state == CClosed) { qunlock(c); return nil; } @@ -1031,34 +1091,9 @@ readcontrol(Conv *c, int n) } qunlock(c); - // hack - this is to avoid gating onto the - // read which will in general result in excessive - // context switches. - // The assumed behavior is that the client will read - // from the control channel until the session is authenticated - // at which point it will open the data channel and - // start reading on that. After the data channel is opened, - // read on the channel are required for packets to - // be delivered to the control channel - - if(c->dataopen) { - sleep(&c->in.controlready, readready, c); - } else { - b = convreadblock(c, n); - if(b == nil) - return nil; - qlock(c); - if(waserror()) { - qunlock(c); - return nil; - } - b = conviput(c, b, 1); - poperror(); - qunlock(c); - if(b != nil) - return b; - } + sleep(&c->in.controlready, readready, c); } + return 0; } static Block * @@ -1068,8 +1103,6 @@ readdata(Conv *c, int n) for(;;) { b = convreadblock(c, n); - if(b == nil) - return nil; qlock(c); if(waserror()) { qunlock(c); @@ -1082,3 +1115,33 @@ readdata(Conv *c, int n) return b; } } + +static void +convreader(void *a) +{ + Conv *c = a; + Block *b; + + qlock(c); + assert(c->reader == 1); + while(c->dataopen == 0) { + qunlock(c); + b = nil; + if(!waserror()) { + b = convreadblock(c, 2000); + poperror(); + } + qlock(c); + if(b == nil) { + convsetstate(c, CClosed); + break; + } + if(!waserror()) { + conviput(c, b, 1); + poperror(); + } + } + c->reader = 0; + qunlock(c); + pexit("hangup", 1); +}