From 13601b6f49db83aa369e382f5242927a46d2a433 Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Tue, 27 Feb 1990 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 1990-02-27 --- port/chan.c | 599 +++++++ port/dev.c | 196 +++ port/devcons.c | 584 +++++++ port/devdup.c | 130 ++ port/devenv.c | 557 ++++++ port/devlance.c | 838 +++++++++ port/devmnt.c | 608 +++++++ port/devpipe.c | 218 +++ port/devproc.c | 380 +++++ port/devroot.c | 140 ++ port/devsrv.c | 203 +++ port/fault.c | 267 +++ port/fcall.c | 379 +++++ port/lib.h | 109 ++ port/page.c | 636 +++++++ port/pgrp.c | 191 +++ port/print.c | 287 ++++ port/proc.c | 541 ++++++ port/stream.c | 886 ++++++++++ port/sturp.c | 808 +++++++++ port/sysfile.c | 508 ++++++ port/sysproc.c | 501 ++++++ power/boot.c | 202 +++ power/boot.h | 4350 +++++++++++++++++++++++++++++++++++++++++++++++ power/clock.c | 190 +++ power/dat.h | 528 ++++++ power/devbit.c | 215 +++ power/devhs.c | 227 +++ power/duart.c | 204 +++ power/errno.h | 45 + power/fcall.h | 89 + power/fns.h | 174 ++ power/io.h | 94 + power/l.s | 454 +++++ power/lock.c | 157 ++ power/main.c | 390 +++++ power/mem.h | 127 ++ power/mmu.c | 103 ++ power/trap.c | 499 ++++++ power/u.h | 15 + power/ureg.h | 41 + 41 files changed, 17670 insertions(+) create mode 100644 port/chan.c create mode 100644 port/dev.c create mode 100644 port/devcons.c create mode 100644 port/devdup.c create mode 100644 port/devenv.c create mode 100644 port/devlance.c create mode 100644 port/devmnt.c create mode 100644 port/devpipe.c create mode 100644 port/devproc.c create mode 100644 port/devroot.c create mode 100644 port/devsrv.c create mode 100644 port/fault.c create mode 100644 port/fcall.c create mode 100644 port/lib.h create mode 100644 port/page.c create mode 100644 port/pgrp.c create mode 100644 port/print.c create mode 100644 port/proc.c create mode 100644 port/stream.c create mode 100644 port/sturp.c create mode 100644 port/sysfile.c create mode 100644 port/sysproc.c create mode 100644 power/boot.c create mode 100644 power/boot.h create mode 100644 power/clock.c create mode 100644 power/dat.h create mode 100644 power/devbit.c create mode 100644 power/devhs.c create mode 100644 power/duart.c create mode 100644 power/errno.h create mode 100644 power/fcall.h create mode 100644 power/fns.h create mode 100644 power/io.h create mode 100644 power/l.s create mode 100644 power/lock.c create mode 100644 power/main.c create mode 100644 power/mem.h create mode 100644 power/mmu.c create mode 100644 power/trap.c create mode 100644 power/u.h create mode 100644 power/ureg.h diff --git a/port/chan.c b/port/chan.c new file mode 100644 index 0000000000000000000000000000000000000000..918d3b7c31ca2a22dbd470502432ac816fe5505b --- /dev/null +++ b/port/chan.c @@ -0,0 +1,599 @@ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "errno.h" + + +struct{ + Lock; + Chan *free; +}chanalloc; + +int +incref(Ref *r) +{ + lock(r); + r->ref++; + unlock(r); + return r->ref; +} + +int +decref(Ref *r) +{ + lock(r); + r->ref--; + unlock(r); + return r->ref; +} + +void +chaninit(void) +{ + int i; + Chan *c; + + chanalloc.free = ialloc(conf.nchan*sizeof(Chan), 0); + + c = chanalloc.free; + for(i=0; ifid = i; + c->next = c+1; + } + c->next = 0; +} + +void +chandevreset(void) +{ + int i; + + for(i=0; inext; + c->flag = 0; + c->ref = 1; + unlock(&chanalloc); + c->offset = 0; + c->mnt = 0; + c->stream = 0; + return c; + } + unlock(&chanalloc); + print("no chans\n"); + if(u == 0) + panic("newchan"); + u->p->state = Wakeme; + alarm(1000, wakeme, u->p); + sched(); + goto loop; +} + +void +close(Chan *c) +{ + if(decref(c) == 0){ + if(!waserror()){ + (*devtab[c->type].close)(c); + poperror(); + } + lock(&chanalloc); + c->next = chanalloc.free; + chanalloc.free = c; + unlock(&chanalloc); + } +} + +int +eqchan(Chan *a, Chan *b, long qmask) +{ + if((a->qid^b->qid) & qmask) + return 0; + if(a->type != b->type) + return 0; + if(a->dev != b->dev) + return 0; + return 1; +} + +/* + * omnt is locked. return with nmnt locked. + */ +Mount* +mountsplit(Mount *omnt) +{ + Mount *nmnt; + + print("mount copy on write\n"); + nmnt = newmount(); + lock(nmnt); + nmnt->term = omnt->term; + nmnt->mountid = omnt->mountid; + nmnt->next = omnt->next; + if(nmnt->next) + incref(nmnt); + nmnt->c = omnt->c; + incref(nmnt->c); + omnt->ref--; + unlock(omnt); + return nmnt; +} + +int +mount(Chan *new, Chan *old, int flag) +{ + int i; + Mtab *mt, *mz; + Mount *mnt, *omnt, *nmnt, *pmnt; + Pgrp *pg; + int isnew; + + if(CHDIR & (old->qid^new->qid)) + error(0, Emount); + if((old->qid&CHDIR)==0 && (flag&MORDER)!=MREPL) + error(0, Emount); + + mz = 0; + isnew = 0; + pg = u->p->pgrp; + lock(pg); + if(waserror()){ + unlock(pg); + nexterror(); + } + /* + * Is old already in mount table? + */ + mt = pg->mtab; + for(i=0; inmtab; i++,mt++){ + if(mt->c==0 && mz==0) + mz = mt; + else if(eqchan(mt->c, old, CHDIR|QPATH)) + goto Found; + } + isnew = 1; + if(mz == 0){ + if(i == conf.nmtab) + error(0, Enomount); + mz = &pg->mtab[i]; + pg->nmtab++; + } + mz->mnt = 0; + mz->c = old; + mt = mz; + + Found: + new->flag = CMOUNT; + if(flag & MCREATE) + new->flag |= CCREATE; + mnt = newmount(); + mnt->c = new; + + switch(flag & MORDER){ + /* + * These two always go at head of list + */ + case MBEFORE: + if(mt->mnt == 0) + error(0, Enotunion); + /* fall through */ + + case MREPL: + omnt = mt->mnt; + if(omnt) + incref(omnt); + mnt->next = omnt; + mt->mnt = mnt; + mnt->term = 1; + if((flag&MORDER) == MBEFORE) + mnt->term = 0; + break; + + /* + * This one never goes at head of list + */ + case MAFTER: + if(mt->mnt == 0) + error(0, Enotunion); + omnt = mt->mnt; + pmnt = 0; + while(!omnt->term){ + lock(omnt); + if(omnt->ref > 1){ + omnt = mountsplit(omnt); + if(pmnt) + pmnt->next = omnt; + else + mt->mnt = omnt; + } + unlock(omnt); + nmnt = omnt->next; + if(nmnt == 0) + panic("MAFTER term"); + pmnt = omnt; + omnt = nmnt; + } + mnt->next = omnt->next; + omnt->next = mnt; + mnt->term = 1; + omnt->term = 0; + break; + } + + incref(new); + if(isnew) + incref(old); + unlock(pg); + poperror(); + return mnt->mountid; +} + +Chan* +clone(Chan *c, Chan *nc) +{ + return (*devtab[c->type].clone)(c, nc); +} + +Chan* +domount(Chan *c) +{ + int i; + ulong mntid; + Mtab *mt; + Mount *mnt; + Pgrp *pg; + Chan *nc, *mc; + + pg = u->p->pgrp; + /* + * Is c in in mount table? + */ + mt = pg->mtab; + for(i=0; inmtab; i++,mt++) + if(mt->c && eqchan(mt->c, c, CHDIR|QPATH)) + goto Found; + /* + * No; c is unaffected + */ + return c; + + /* + * Yes; move c through table + */ + Found: + lock(pg); + if(!eqchan(mt->c, c, CHDIR|QPATH)){ /* table changed underfoot */ + print("domount: changed underfoot?\n"); + unlock(pg); + return c; + } + mnt = mt->mnt; + mntid = mnt->mountid; + mc = mnt->c; + incref(mc); + unlock(pg); + if(waserror()){ + close(mc); + nexterror(); + } + nc = clone(mc, 0); + close(mc); + poperror(); + close(c); + nc->mnt = mnt; + nc->mountid = mntid; + return nc; +} + +Chan* +walk(Chan *ac, char *name, int domnt) +{ + Mount *mnt; + int first = 1; + Chan *c = ac; + Chan *nc, *mc; + Pgrp *pg = u->p->pgrp; + + /* + * name may be empty if the file name is "/", "#c" etc. + */ + Again: + if(name[0] && (*devtab[c->type].walk)(c, name)==0){ + if(!(c->flag&CMOUNT)) + goto Notfound; + mnt = c->mnt; + if(mnt == 0) + panic("walk"); + lock(pg); + if(mnt->term){ + unlock(pg); + goto Notfound; + } + if(c->mountid != mnt->mountid){ + print("walk: changed underfoot?\n"); + unlock(pg); + goto Notfound; + } + mnt = mnt->next; + mc = mnt->c; + incref(mc); + unlock(pg); + if(waserror()){ + close(mc); + nexterror(); + } + if(mnt == 0) + panic("walk 1"); + nc = clone(mc, 0); + close(mc); + poperror(); + if(!first) + close(c); + nc->mnt = mnt; + c = nc; + first = 0; + goto Again; + } + + if(name[0]) /* walk succeeded */ + c->flag &= ~CMOUNT; + + if(!first) + close(ac); + + if(domnt) + return domount(c); + return c; + + Notfound: + if(!first) + close(c); + return 0; +} + +/* + * c is a mounted non-creatable directory. find a creatable one. + */ +Chan* +createdir(Chan *c) +{ + Mount *mnt; + Pgrp *pg = u->p->pgrp; + Chan *mc, *nc; + + lock(pg); + if(waserror()){ + unlock(pg); + nexterror(); + } + mnt = c->mnt; + if(c->mountid != mnt->mountid){ + print("createdir: changed underfoot?\n"); + error(0, Enocreate); + } + do{ + if(mnt->term) + error(0, Enocreate); + mnt = mnt->next; + }while(!(mnt->c->flag&CCREATE)); + mc = mnt->c; + incref(mc); + unlock(pg); + if(waserror()){ + close(mc); + nexterror(); + } + nc = clone(mc, 0); + poperror(); + close(c); + close(mc); + nc->mnt = mnt; + return nc; +} + +/* + * Turn a name into a channel. + * &name[0] is known to be a valid address. It may be a kernel address. + */ +Chan* +namec(char *name, int amode, int omode, ulong perm) +{ + Chan *c, *nc; + int t; + int mntok; + char *elem = u->elem; + + if(name[0] == 0) + error(0, Enonexist); + mntok = 1; + if(name[0] == '/'){ + c = clone(u->slash, 0); + /* + * Skip leading slashes. + */ + name = skipslash(name); + }else if(name[0] == '#'){ + mntok = 0; + if(!((ulong)name & KZERO)) + validaddr((ulong)(name+1), 2, 0); + if(name[1]=='|' || ('A'<=name[1] && name[1]<='Z')) + error(0, Enonexist); + t = devno(name[1], 1); + if(t == -1) + error(0, Ebadsharp); + name += 2; + if(*name == '/'){ + name = skipslash(name); + elem[0]=0; + }else + name = nextelem(name, elem); + c = (*devtab[t].attach)(elem); + }else + c = clone(u->dot, 0); + + if(waserror()){ + close(c); + nexterror(); + } + + name = nextelem(name, elem); + if(mntok) + if(!(amode==Amount && elem[0]==0)) /* don't domount on dot or slash */ + c = domount(c); /* see case Atodir below */ + + /* + * How to treat the last element of the name depends on the operation. + * Therefore do all but the last element by the easy algorithm. + */ + while(*name){ + if((nc=walk(c, elem, mntok)) == 0) + error(0, Enonexist); + c = nc; + name = nextelem(name, elem); + } + /* + * Last element; act according to type of access. + */ + + switch(amode){ + case Aaccess: + if((nc=walk(c, elem, mntok)) == 0) + error(0, Enonexist); + c = nc; + break; + + case Atodir: + /* + * Directories (e.g. for cd) are left before the mount point, + * so one may mount on / or . and see the effect. + */ + if((nc=walk(c, elem, 0)) == 0) + error(0, Enonexist); + c = nc; + if(!(c->qid & CHDIR)) + error(0, Enotdir); + break; + + case Aopen: + if((nc=walk(c, elem, mntok)) == 0) + error(0, Enonexist); + c = nc; + Open: + c = (*devtab[c->type].open)(c, omode); + break; + + case Amount: + /* + * When mounting on an already mounted upon directory, one wants + * the second mount to be attached to the original directory, not + * the replacement. + */ + if((nc=walk(c, elem, 0)) == 0) + error(0, Enonexist); + c = nc; + break; + + case Acreate: + if((nc=walk(c, elem, 1)) != 0){ + c = nc; + omode |= OTRUNC; + goto Open; + } + if((c->flag&(CMOUNT|CCREATE)) == CMOUNT) + c = createdir(c); + (*devtab[c->type].create)(c, elem, omode, perm); + break; + + default: + panic("unknown namec access %d\n", amode); + } + poperror(); + return c; +} + +/* + * name[0] is addressable. + */ +char* +skipslash(char *name) +{ + while(*name == '/'){ + if(((ulong)name&KZERO)==0 && (((ulong)name+1)&(BY2PG-1))==0) + validaddr((ulong)name+1, 1, 0); + name++; + } + return name; +} + +char isfrog[]={ + /*NUL*/ 1, 1, 1, 1, 1, 1, 1, 1, + /*BKS*/ 1, 1, 1, 1, 1, 1, 1, 1, + /*DLE*/ 1, 1, 1, 1, 1, 1, 1, 1, + /*CAN*/ 1, 1, 1, 1, 1, 1, 1, 1, + [' '] 1, + ['/'] 1, + [0x7f] 1, +}; + +/* + * name[0] should not be a slash. + * Advance name to next element in path, copying current element into elem. + * Return pointer to next element, skipping slashes. + * &name[0] is known to be a valid address. + */ +char* +nextelem(char *name, char *elem) +{ + int i, user, c; + char *end, *e; + + if(*name == '/') + error(0, Efilename); + end = vmemchr(name, 0, NAMELEN); + if(end == 0){ + end = vmemchr(name, '/', NAMELEN); + if(end == 0) + error(0, Efilename); + }else{ + e = memchr(name, '/', end-name); + if(e) + end = e; + } + while(name < end){ + c = *name++; + if((c&0x80) || isfrog[c]) + error(0, Ebadchar); + *elem++ = c; + } + *elem = 0; + return skipslash(name); +} + +void +isdir(Chan *c) +{ + if(c->qid & CHDIR) + return; + error(0, Enotdir); +} diff --git a/port/dev.c b/port/dev.c new file mode 100644 index 0000000000000000000000000000000000000000..cac778c467536fa6af4bd82469fa68fa065f1858 --- /dev/null +++ b/port/dev.c @@ -0,0 +1,196 @@ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "errno.h" + +#define DEVTAB +#include "devtab.h" + +#include "fcall.h" + +int +devno(int c, int user) +{ + char *s; + + s = strchr(devchar, c); + if(s==0 || c==0){ + if(user) + return -1; + panic("devno %c 0x%ux", c, c); + } + return s - devchar; +} + +void +devdir(Chan *c, long qid, char *n, long length, long perm, Dir *db) +{ + strcpy(db->name, n); + db->qid = qid; + db->type = devchar[c->type]; + db->dev = c->dev; + if(qid & CHDIR) + db->mode = CHDIR|perm; + else + db->mode = perm; + db->atime = seconds(); + db->mtime = db->atime; + db->hlength = 0; + db->length = length; + db->uid = 0; + db->gid = 0; +} + +int +devgen(Chan *c, Dirtab *tab, int ntab, int i, Dir *dp) +{ + if(tab==0 || i>=ntab) + return -1; + tab += i; + devdir(c, tab->qid, tab->name, tab->length, tab->perm, dp); + return 1; +} + +Chan * +devattach(int tc, char *spec) +{ + Chan *c; + + c = newchan(); + c->qid = CHDIR; + c->type = devno(tc, 0); + return c; +} + +Chan * +devclone(Chan *c, Chan *nc) +{ + if(nc == 0) + nc = newchan(); + nc->type = c->type; + nc->mode = c->mode; + nc->qid = c->qid; + nc->offset = c->offset; + nc->dev = c->dev; + nc->flag = c->flag; + nc->mnt = c->mnt; + return nc; +} + +int +devwalk(Chan *c, char *name, Dirtab *tab, int ntab, Devgen *gen) +{ + long i; + Dir dir; + + isdir(c); + if(name[0]=='.' && name[1]==0) + return 1; + for(i=0;; i++) + switch((*gen)(c, tab, ntab, i, &dir)){ + case -1: + u->error.type = 0; + u->error.dev = 0; + u->error.code = Enonexist; + return 0; + case 0: + continue; + case 1: + if(strcmp(name, dir.name) == 0){ + c->qid = dir.qid; + return 1; + } + continue; + } +} + +void +devstat(Chan *c, char *db, Dirtab *tab, int ntab, Devgen *gen) +{ + int i; + Dir dir; + + for(i=0;; i++) + switch((*gen)(c, tab, ntab, i, &dir)){ + case -1: + /* + * devices with interesting directories usually don't get + * here, which is good because we've lost the name by now. + */ + if(c->qid & CHDIR){ + devdir(c, c->qid, ".", 0L, CHDIR|0700, &dir); + convD2M(&dir, db); + return; + } + panic("devstat"); + case 0: + break; + case 1: + if(c->qid == dir.qid){ + convD2M(&dir, db); + return; + } + break; + } +} + +long +devdirread(Chan *c, char *d, long n, Dirtab *tab, int ntab, Devgen *gen) +{ + long k, l, m; + Dir dir; + + k = c->offset/DIRLEN; + l = (c->offset+n)/DIRLEN; + n = 0; + for(m=k; moffset += DIRLEN; + break; + + case 1: + convD2M(&dir, d); + n += DIRLEN; + d += DIRLEN; + m++; + break; + } + return n; +} + +Chan * +devopen(Chan *c, int omode, Dirtab *tab, int ntab, Devgen *gen) +{ + int i; + Dir dir; + static int access[] = { 0400, 0200, 0600, 0100 }; + + for(i=0;; i++) + switch((*gen)(c, tab, ntab, i, &dir)){ + case -1: + /* Deal with union directories? */ + goto Return; + case 0: + break; + case 1: + if(c->qid == dir.qid){ + if((access[omode&3] & dir.mode) == access[omode&3]) + goto Return; + error(0, Eperm); + } + break; + } + Return: + c->offset = 0; + if((c->qid&CHDIR) && omode!=OREAD) + error(0, Eperm); + c->mode = openmode(omode); + c->flag |= COPEN; + return c; +} diff --git a/port/devcons.c b/port/devcons.c new file mode 100644 index 0000000000000000000000000000000000000000..8bb8264991a72aca398e73dc2e1c56279cee32b4 --- /dev/null +++ b/port/devcons.c @@ -0,0 +1,584 @@ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" +#include "errno.h" + +#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 */ + +void +printinit(void) +{ + + printq.in = printq.buf; + printq.out = printq.buf; + lock(&printq); /* allocate lock */ + unlock(&printq); + + 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); + + duartinit(); +} + +/* + * 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. + */ +void +puts(char *s, int n) +{ + if(!printq.printing){ + printq.printing = 1; + printq.c = *s++; + n--; + } + memcpy(printq.in, s, n); + printq.in += n; + if(printq.in >= printq.buf+sizeof(printq.buf)) + printq.in = printq.buf; +} + +/* + * 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. + */ +void +putstrn(char *str, int n) +{ + int s, c, m; + char *t; + + s = splhi(); + lock(&printq); + while(n > 0){ + if(*str == '\n') + puts("\r", 1); + m = printq.buf+sizeof(printq.buf) - printq.in; + if(n < m) + m = n; + t = memchr(str+1, '\n', m-1); + if(t) + if(t-str < m) + m = t - str; + puts(str, m); + n -= m; + str += m; + } + unlock(&printq); + splx(s); +} + +int +cangetc(IOQ *q) +{ + return q->in != q->out; +} + +int +isbrkc(IOQ *q) +{ + uchar *p; + + for(p=q->out; p!=q->in; ){ + if(*p==0x04 || *p=='\n') + return 1; + p++; + if(p >= q->buf+sizeof(q->buf)) + p = q->buf; + } + return 0; +} + +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, ...) +{ + char *out; + + out = donprint(s, s+PRINTSIZE, fmt, (&fmt+1)); + return out-s; +} + +int +print(char *fmt, ...) +{ + char buf[PRINTSIZE]; + int n; + + n = donprint(buf, buf+sizeof(buf), fmt, (&fmt+1)) - buf; + putstrn(buf, n); + return n; +} + +void +panic(char *fmt, ...) +{ + char buf[PRINTSIZE]; + int n; + + strcpy(buf, "panic: "); + n = donprint(buf+7, buf+sizeof(buf), fmt, (&fmt+1)) - buf; + buf[n] = '\n'; + putstrn(buf, n+1); + exit(); +} + +int +pprint(char *fmt, ...) +{ + char buf[2*PRINTSIZE]; + Chan *c; + int n; + + c = u->fd[2]; + if(c==0 || (c->mode!=OWRITE && c->mode!=ORDWR)) + return; + n = sprint(buf, "%s %d: ", u->p->text, u->p->pid); + n = donprint(buf+n, buf+sizeof(buf), fmt, (&fmt+1)) - buf; + qlock(c); + if(waserror()){ + qunlock(c); + return; + } + (*devtab[c->type].write)(c, buf, n); + c->offset += n; + qunlock(c); + return n; +} + +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; +} + +void +echo(int c) +{ + char ch; + /* + * ^t hack BUG + */ + if(c == 0x14) + DEBUG(); + else if(c == 0x0c) + LANCEDEBUG(); + else if(c == 0x02) + LANCEPRDEBQ(); + if(c == 0x15) + putstrn("^U\n", 3); + else{ + ch = c; + putstrn(&ch, 1); + } +} + +/* + * Put character into read queue at interrupt time. + * Always called splhi from proc 0. + */ +void +kbdchar(int c) +{ + if(c == '\r') + c = '\n'; + echo(c); + *kbdq.in++ = c; + if(kbdq.in == kbdq.buf+sizeof(kbdq.buf)) + kbdq.in = kbdq.buf; + if(c=='\n' || c==0x04) + wakeup(&kbdq.r); +} + +void +printslave(void) +{ + int c; + + c = printq.c; + if(c){ + printq.c = 0; + duartxmit(c); + } +} + +int +consactive(void) +{ + return printq.in != printq.out; +} + +/* + * I/O interface + */ +enum{ + Qdir, + Qcons, + Qcputime, + Qnull, + Qpgrpid, + Qpid, + Qppid, + Qtime, + Quser, +}; + +Dirtab consdir[]={ + "cons", Qcons, 0, 0600, + "cputime", Qcputime, 72, 0600, + "null", Qnull, 0, 0600, + "pgrpid", Qpgrpid, 12, 0600, + "pid", Qpid, 12, 0600, + "ppid", Qppid, 12, 0600, + "time", Qtime, 12, 0600, + "user", Quser, 0, 0600, +}; + +#define NCONS (sizeof consdir/sizeof(Dirtab)) + +ulong boottime; /* seconds since epoch at boot */ + +long +seconds(void) +{ + return boottime + MACHP(0)->ticks*MS2HZ/1000; +} + +int +readnum(ulong off, char *buf, ulong n, ulong val, int size) +{ + char tmp[64]; + Op op = (Op){ tmp, tmp+sizeof(tmp), &val, size-1, 0, FUNSIGN|FLONG }; + + numbconv(&op, 10); + tmp[size-1] = ' '; + off %= size; + if(off+n > size) + n = size-off; + memcpy(buf, tmp+off, n); + return n; +} + +int +readstr(ulong off, char *buf, ulong n, char *str) +{ + int size; + + size = strlen(str); + off %= size; + if(off+n > size) + n = size-off; + memcpy(buf, str+off, n); + return n; +} + +void +consreset(void) +{ +} + +void +consinit(void) +{ +} + +Chan* +consattach(char *spec) +{ + return devattach('c', spec); +} + +Chan* +consclone(Chan *c, Chan *nc) +{ + return devclone(c, nc); +} + +int +conswalk(Chan *c, char *name) +{ + return devwalk(c, name, consdir, NCONS, devgen); +} + +void +consstat(Chan *c, char *dp) +{ + devstat(c, dp, consdir, NCONS, devgen); +} + +Chan* +consopen(Chan *c, int omode) +{ + if(c->qid==Quser && omode==(OWRITE|OTRUNC)){ + /* truncate? */ + if(strcmp(u->p->pgrp->user, "bootes") == 0) /* BUG */ + u->p->pgrp->user[0] = 0; + else + error(0, Eperm); + } + return devopen(c, omode, consdir, NCONS, devgen); +} + +void +conscreate(Chan *c, char *name, int omode, ulong perm) +{ + error(0, Eperm); +} + +void +consclose(Chan *c) +{ +} + +long +consread(Chan *c, void *buf, long n) +{ + int ch, i, j, k; + ulong l; + uchar *out; + char *cbuf = buf; + char *user; + int userlen; + char tmp[6*NUMSIZE]; + + if(n <= 0) + return n; + switch(c->qid&~CHDIR){ + case Qdir: + return devdirread(c, buf, n, consdir, NCONS, devgen); + + case Qcons: + qlock(&kbdq); + while(!cangetc(&lineq)){ + sleep(&kbdq.r, (int(*)(void*))isbrkc, &kbdq); + do{ + ch = getc(&kbdq); + switch(ch){ + case '\b': + if(lineq.in != lineq.out){ + if(lineq.in == lineq.buf) + lineq.in = lineq.buf+sizeof(lineq.buf); + lineq.in--; + } + break; + case 0x15: + lineq.in = lineq.out; + break; + default: + *lineq.in++ = ch; + if(lineq.in == lineq.buf+sizeof(lineq.buf)) + lineq.in = lineq.buf; + } + }while(ch!='\n' && ch!=0x04); + } + i = 0; + while(n>0){ + ch = getc(&lineq); + if(ch == 0x04 || ch == -1) + break; + i++; + *cbuf++ = ch; + --n; + } + qunlock(&kbdq); + return i; + + case Qcputime: + k = c->offset % sizeof tmp; + if(k+n > sizeof tmp) + n = sizeof tmp - k; + /* easiest to format in a separate buffer and copy out */ + for(i=0; i<6 && NUMSIZE*ip->time[i]; + if(i == TReal) + l = MACHP(0)->ticks - l; + l *= MS2HZ; + readnum(0, tmp+NUMSIZE*i, NUMSIZE, l, NUMSIZE); + } + memcpy(buf, tmp+k, n); + return n; + + case Qpgrpid: + return readnum(c->offset, buf, n, u->p->pgrp->pgrpid, NUMSIZE); + + case Qpid: + return readnum(c->offset, buf, n, u->p->pid, NUMSIZE); + + case Qppid: + return readnum(c->offset, buf, n, u->p->parentpid, NUMSIZE); + + case Qtime: + return readnum(c->offset, buf, n, boottime+MACHP(0)->ticks/(1000/MS2HZ), 12); + + case Quser: + return readstr(c->offset, buf, n, u->p->pgrp->user); + + case Qnull: + return 0; + + default: + panic("consread %lux\n", c->qid); + return 0; + } +} + +long +conswrite(Chan *c, void *va, long n) +{ + char cbuf[64]; + char buf[256]; + long l, m; + char *a = va; + + switch(c->qid){ + case Qcons: + /* + * Damn. Can't page fault in putstrn, so copy the data locally. + */ + l = n; + while(l > 0){ + m = l; + if(m > sizeof buf) + m = sizeof buf; + memcpy(buf, a, m); + putstrn(a, m); + a += m; + l -= m; + } + break; + + case Qtime: + if(n<=0 || boottime!=0) /* only one write please */ + return 0; + if(n >= sizeof cbuf) + n = sizeof cbuf - 1; + memcpy(cbuf, a, n); + cbuf[n-1] = 0; + boottime = strtoul(a, 0, 0); + break; + + case Quser: + if(u->p->pgrp->user[0]) /* trying to overwrite /dev/user */ + error(0, Eperm); + if(c->offset >= NAMELEN-1) + return 0; + if(c->offset+n >= NAMELEN-1) + n = NAMELEN-1 - c->offset; + memcpy(u->p->pgrp->user+c->offset, a, n); + u->p->pgrp->user[c->offset+n] = 0; + break; + + case Qcputime: + case Qpgrpid: + case Qpid: + case Qppid: + error(0, Eperm); + + case Qnull: + break; + default: + error(0, Egreg); + } + return n; +} + +void +consremove(Chan *c) +{ + error(0, Eperm); +} + +void +conswstat(Chan *c, char *dp) +{ + error(0, Eperm); +} + +void +conserrstr(Error *e, char *buf) +{ + rooterrstr(e, buf); +} + +void +consuserstr(Error *e, char *buf) +{ + strcpy(buf, u->p->pgrp->user); +} diff --git a/port/devdup.c b/port/devdup.c new file mode 100644 index 0000000000000000000000000000000000000000..0646a5046b2e1a8149b5701858d8b9bdd298056d --- /dev/null +++ b/port/devdup.c @@ -0,0 +1,130 @@ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "errno.h" + +#include "devtab.h" + + +int +dupgen(Chan *c, Dirtab *tab, int ntab, int s, Dir *dp) +{ + char buf[8]; + Chan *f; + static int perm[] = { 0400, 0200, 0600, 0 }; + + if(s >= NFD) + return -1; + if((f=u->fd[s]) == 0) + return 0; + sprint(buf, "%ld", s); + devdir(c, s, buf, 0, perm[f->mode&3], dp); + return 1; +} + +void +dupinit(void) +{ +} + +void +dupreset(void) +{ +} + +Chan * +dupattach(char *spec) +{ + return devattach('d', spec); +} + +Chan * +dupclone(Chan *c, Chan *nc) +{ + return devclone(c, nc); +} + +int +dupwalk(Chan *c, char *name) +{ + return devwalk(c, name, (Dirtab *)0, 0, dupgen); +} + +void +dupstat(Chan *c, char *db) +{ + devstat(c, db, (Dirtab *)0, 0L, dupgen); +} + +Chan * +dupopen(Chan *c, int omode) +{ + Chan *f; + + if(c->qid == CHDIR){ + if(omode != 0) + error(0, Eisdir); + c->mode = 0; + c->flag |= COPEN; + c->offset = 0; + return c; + } + fdtochan(c->qid, openmode(omode)); /* error check only */ + f = u->fd[c->qid]; + close(c); + incref(f); + return f; +} + +void +dupcreate(Chan *c, char *name, int omode, ulong perm) +{ + error(0, Eperm); +} + +void +dupremove(Chan *c) +{ + error(0, Eperm); +} + +void +dupwstat(Chan *c, char *dp) +{ + error(0, Egreg); +} + +void +dupclose(Chan *c) +{ +} + +long +dupread(Chan *c, void *va, long n) +{ + char *a = va; + + if(c->qid != CHDIR) + panic("dupread"); + return devdirread(c, a, n, (Dirtab *)0, 0L, dupgen); +} + +long +dupwrite(Chan *c, void *va, long n) +{ + panic("dupwrite"); +} + +void +duperrstr(Error *e, char *buf) +{ + rooterrstr(e, buf); +} + +void +dupuserstr(Error *e, char *buf) +{ + consuserstr(e, buf); +} diff --git a/port/devenv.c b/port/devenv.c new file mode 100644 index 0000000000000000000000000000000000000000..ad30d487f5712f88eff2b912e27affb7c6a3eaf4 --- /dev/null +++ b/port/devenv.c @@ -0,0 +1,557 @@ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "errno.h" + +#include "devtab.h" + +/* + * An environment value is kept in some number of contiguous + * Envvals, with the Env's val pointing at the first. + * Envvals are allocated from the end of a fixed arena, which + * is compacted when the arena end is reached. + * A `piece' (number of contiguous Envvals) is free to be + * reclaimed if its e pointer is 0. + * + * Locking: an env's val can change by compaction, so lock + * an env before using its value. A pgrp env[] slot can go + * to 0 and the corresponding env freed (by envremove()), so + * lock the pgrp around the use of a value retrieved from a slot. + * Lock in order: pgrp, envalloc, env (but ok to skip envalloc + * lock if there is no possibility of blocking). + */ + +struct Envval +{ + ulong n; /* number of Envval's (including this) in this piece */ + ulong len; /* how much of dat[] is valid */ + Env *e; /* the Env whose val points here */ + char dat[4]; /* possibly extends into further envvals after this */ +}; + +/* number of contiguous Envvals needed to hold n characters */ +#define EVNEEDED(n) ((n)<4? 1 : 1+((n)+(sizeof(Envval))-1-4)/(sizeof(Envval))) + +struct +{ + Lock; + Envval *arena; + Envval *vfree; + Envval *end; + Env *efree; + Env *earena; +}envalloc; + +void compactenv(Env *, ulong); + +void +envreset(void) +{ + int i, n; + + n = EVNEEDED(conf.nenvchar); + envalloc.arena = ialloc(n*sizeof(Envval), 0); + envalloc.vfree = envalloc.arena; + envalloc.end = envalloc.arena+n; + + envalloc.earena = ialloc(conf.nenv*sizeof(Env), 0); + envalloc.efree = envalloc.earena; + for(i=0; ival points at a value big enough to hold nchars chars. + * The caller should fix e->val->len. + * envalloc and e should be locked + */ +void +growenval(Env *e, ulong nchars) +{ + Envval *p; + ulong n, nfree; + + n = EVNEEDED(nchars); + if(p = e->val){ /* assign = */ + if(p->n < n){ + if(p+p->n == envalloc.vfree){ + compactenv(e, n - p->n); + p = e->val; + envalloc.vfree += n - p->n; + }else{ + compactenv(e, n); + p = envalloc.vfree; + envalloc.vfree += n; + memcpy(p, e->val, e->val->n*sizeof(Envval)); + p->e = e; + e->val->e = 0; + e->val = p; + } + p->n = n; + } + }else{ + compactenv(e, n); + p = envalloc.vfree; + envalloc.vfree += n; + p->n = n; + p->e = e; + e->val = p; + } +} + +/* + * Make sure there is room for n Envval's at the end of envalloc.vfree. + * Call this with envalloc and e locked. + */ +void +compactenv(Env *e, ulong n) +{ + Envval *p1, *p2; + Env *p2e; + + if(envalloc.end-envalloc.vfree >= n) + return; + p1 = envalloc.arena; /* dest */ + p2 = envalloc.arena; /* source */ + while(p2 < envalloc.vfree){ + p2e = p2->e; + if(p2e == 0){ + Free: + p2 += p2->n; + continue; + } + if(p2e=envalloc.earena+conf.nenv){ + print("%lux not an env\n", p2e); + panic("compactenv"); + } + if(p1 != p2){ + if(p2e != e) + lock(p2e); + if(p2->e != p2e){ /* freed very recently */ + print("compactenv p2e moved\n"); + if(p2->e) + panic("compactenv p2->e %lux\n", p2->e); + unlock(p2e); + goto Free; + } + if(p2+p2->n > envalloc.end) + panic("compactpte copying too much"); + memcpy(p1, p2, p2->n*sizeof(Envval)); + p2e->val = p1; + if(p2e != e) + unlock(p2e); + } + p2 += p1->n; + p1 += p1->n; + } + envalloc.vfree = p1; + if(envalloc.end-envalloc.vfree < n){ + print("env compact failed\n"); + error(0, Enoenv); + } +} + +/* + * Return an env with a copy of e's value. + * envalloc and e should be locked, + * and the value returned will be locked too. + */ +Env * +copyenv(Env *e, int trunc) +{ + Env *ne; + int n; + + ne = envalloc.efree; + if(!ne){ + print("out of envs\n"); + error(0, Enoenv); + } + envalloc.efree = ne->next; + lock(ne); + if(waserror()){ + unlock(ne); + nexterror(); + } + ne->next = 0; + ne->pgref = 1; + strncpy(ne->name, e->name, NAMELEN); + if(e->val && !trunc){ + n = e->val->len; + /* + * growenval can't hold the lock on another env + * because compactenv assumes only one is held + */ + unlock(e); + growenval(ne, n); + lock(e); + if(n != e->val->len){ + print("e changed in copyenv\n"); + if(n > ne->val->len) + n = ne->val->len; + } + if((char*)(ne->val+ne->val->n) < ne->val->dat+n) + panic("copyenv corrupt"); + memcpy(ne->val->dat, e->val->dat, n); + ne->val->len = n; + } + poperror(); + return ne; +} + +int +envgen(Chan *c, Dirtab *tab, int ntab, int s, Dir *dp) +{ + Env *e; + Pgrp *pg; + int ans; + + pg = u->p->pgrp; + lock(pg); + if(s >= pg->nenv) + ans = -1; + else{ + e = pg->etab[s].env; + if(e == 0) + ans = 0; + else{ + lock(e); + devdir(c, s+1, e->name, e->val? e->val->len : 0, 0666, dp); + unlock(e); + ans = 1; + } + } + unlock(pg); + return ans; +} + +Chan* +envattach(char *spec) +{ + return devattach('e', spec); +} + +Chan* +envclone(Chan *c, Chan *nc) +{ + Pgrp *pg; + + if(!(c->qid&CHDIR)){ + pg = u->p->pgrp; + lock(pg); + pg->etab[c->qid-1].chref++; + unlock(pg); + } + return devclone(c, nc); +} + +int +envwalk(Chan *c, char *name) +{ + Pgrp *pg; + + if(devwalk(c, name, 0, 0, envgen)){ + if(!(c->qid&CHDIR)){ + pg = u->p->pgrp; + lock(pg); + pg->etab[c->qid-1].chref++; + unlock(pg); + return 1; + } + } + return 0; +} + +void +envstat(Chan *c, char *db) +{ + devstat(c, db, 0, 0, envgen); +} + +Chan * +envopen(Chan *c, int omode) +{ + Env *e, *ne; + Envp *ep; + Pgrp *pg; + + if(omode & (OWRITE|OTRUNC)){ + if(c->qid & CHDIR) + error(0, Eperm); + pg = u->p->pgrp; + lock(pg); + ep = &pg->etab[c->qid-1]; + e = ep->env; + if(!e){ + unlock(pg); + error(0, Egreg); + } + lock(&envalloc); + lock(e); + if(waserror()){ + unlock(e); + unlock(&envalloc); + nexterror(); + } + if(e->pgref == 0) + panic("envopen"); + if(e->pgref == 1){ + if((omode&OTRUNC) && e->val){ + e->val->e = 0; + e->val = 0; + } + }else{ + ne = copyenv(e, omode&OTRUNC); + e->pgref--; /* it will still be positive */ + ep->env = ne; + unlock(ne); + } + poperror(); + unlock(e); + unlock(&envalloc); + unlock(pg); + } + c->mode = openmode(omode); + c->flag |= COPEN; + c->offset = 0; + return c; +} + +void +envcreate(Chan *c, char *name, int omode, ulong perm) +{ + Env *e; + Pgrp *pg; + int i; + + if(c->qid != CHDIR) + error(0, Eperm); + pg = u->p->pgrp; + lock(pg); + lock(&envalloc); + if(waserror()){ + unlock(&envalloc); + unlock(pg); + nexterror(); + } + e = envalloc.efree; + if(e == 0){ + print("out of envs\n"); + error(0,Enoenv); + } + envalloc.efree = e->next; + e->next = 0; + e->pgref = 1; + strncpy(e->name, name, NAMELEN); + if(pg->nenv == conf.npgenv){ + for(i = 0; inenv; i++) + if(pg->etab[i].chref == 0) + break; + if(i == pg->nenv){ + print("out of pgroup envs\n"); + error(0, Enoenv); + } + }else + i = pg->nenv++; + c->qid = i+1; + pg->etab[i].env = e; + pg->etab[i].chref = 1; + unlock(&envalloc); + unlock(pg); + c->offset = 0; + c->mode = openmode(omode); + poperror(); + c->flag |= COPEN; +} + +void +envremove(Chan *c) +{ + Env *e; + Envp *ep; + Pgrp *pg; + + if(c->qid & CHDIR) + error(0, Eperm); + pg = u->p->pgrp; + lock(pg); + ep = &pg->etab[c->qid-1]; + e = ep->env; + if(!e){ + unlock(pg); + error(0, Enonexist); + } + ep->env = 0; + ep->chref--; + envpgclose(e); + unlock(pg); +} + +void +envwstat(Chan *c, char *db) +{ int dumpenv(void); + dumpenv(); /*DEBUG*/ + print("envwstat\n"); + error(0, Egreg); +} + +void +envclose(Chan * c) +{ + Pgrp *pg; + + if(c->qid & CHDIR) + return; + pg = u->p->pgrp; + lock(pg); + pg->etab[c->qid-1].chref--; + unlock(pg); +} + +void +envpgclose(Env *e) +{ + lock(&envalloc); + lock(e); + if(--e->pgref <= 0){ + if(e->val){ + e->val->e = 0; + e->val = 0; + } + e->next = envalloc.efree; + envalloc.efree = e; + } + unlock(e); + unlock(&envalloc); +} + +long +envread(Chan *c, void *va, long n) +{ + Env *e; + Envval *ev; + char *p; + long vn; + Pgrp *pg; + char *a = va; + + if(c->qid & CHDIR) + return devdirread(c, a, n, 0, 0, envgen); + pg = u->p->pgrp; + lock(pg); + e = pg->etab[c->qid-1].env; + if(!e){ + unlock(pg); + error(0, Eio); + } + lock(e); + ev = e->val; + vn = ev? e->val->len : 0; + if(c->offset+n > vn) + n = vn - c->offset; + if(n <= 0) + n = 0; + else + memcpy(a, ev->dat+c->offset, n); + unlock(e); + unlock(pg); + return n; +} + +long +envwrite(Chan *c, void *va, long n) +{ + Env *e; + char *p; + Envval *ev; + long vn; + Pgrp *pg; + char *a = va; + + if(n <= 0) + return 0; + pg = u->p->pgrp; + lock(pg); + e = pg->etab[c->qid-1].env; /* caller checks for CHDIR */ + if(!e){ + unlock(pg); + error(0, Eio); + } + lock(&envalloc); + lock(e); + if(waserror()){ + unlock(e); + unlock(&envalloc); + unlock(pg); + nexterror(); + } + if(e->pgref>1) + panic("envwrite to non-duped env"); + growenval(e, c->offset+n); + ev = e->val; + vn = ev? ev->len : 0; + if(c->offset > vn) + error(0, Egreg); /* perhaps should zero fill */ + memcpy(ev->dat+c->offset, a, n); + e->val->len = c->offset+n; + poperror(); + unlock(e); + unlock(&envalloc); + unlock(pg); + return n; +} + +void +dumpenv(void) +{ + Env *e; + Envp *ep; + Envval *ev; + Pgrp *pg; + int i; + char hold; + + pg = u->p->pgrp; + for(ep=pg->etab, i=0; inenv; i++, ep++) + print("P%d(%lux %d)",i, ep->env, ep->chref); + for(e=envalloc.earena; e<&envalloc.earena[conf.nenv]; e++) + if(e->pgref){ + print("E{%lux %d '%s'}[", e, e->pgref, e->name); + if(e->val){ + hold = e->val->dat[e->val->len]; + e->val->dat[e->val->len] = 0; + print("%s", e->val->dat); + e->val->dat[e->val->len] = hold; + } + print("]"); + }else if(e->val) + print("whoops, free env %lux has val=%lux\n",e,e->val); + for(i=0, e=envalloc.efree; e; e=e->next) + i++; + print("\n%d free envs", i); + for(i=0, ev=envalloc.arena; evn) + if(!ev->e) + i += ev->n*sizeof(Envval); + print(" %d free enval chars\n", i+((char *)envalloc.end-(char*)envalloc.vfree)); +} + +void +envuserstr(Error *e, char *buf) +{ + consuserstr(e, buf); +} + +void +enverrstr(Error *e, char *buf) +{ + rooterrstr(e, buf); +} + diff --git a/port/devlance.c b/port/devlance.c new file mode 100644 index 0000000000000000000000000000000000000000..d1518fc524a49d57c609ddfaa49025f967dea5c9 --- /dev/null +++ b/port/devlance.c @@ -0,0 +1,838 @@ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" +#include "errno.h" +#include "devtab.h" +/* + * configuration parameters + */ +enum { + Ntypes= 8, /* max number of ethernet packet types */ + LogNrrb= 7, /* log of number of receive buffers */ + Nrrb= (1<>16)&0xF) +#define LADDR(a) (((ulong)a)&0xFFFF) + +/* + * one per ethernet packet type + */ +typedef struct { + QLock; + int type; /* ethernet type */ + Queue *q; +} Ethertype; + +/* + * circular debug queue (first 44 bytes of the last Ndpkt packets) + */ +typedef struct { + uchar d[6]; + uchar s[6]; + uchar type[2]; + uchar data[40]; +} Dpkt; +typedef struct { + Lock; + int next; + char *tag[Ndpkt]; + int len[Ndpkt]; + Dpkt p[Ndpkt]; +} Debqueue; + +/* + * lance state + */ +typedef struct { + QLock; + + int inited; + uchar ea[6]; /* our ether addr */ + uchar *lmp; /* location of parity test */ + ushort *rap; /* lance address register */ + ushort *rdp; /* lance data register */ + + Rendez rr; /* rendezvous for an input buffer */ + ushort rl; /* first rcv Message belonging to Lance */ + ushort rc; /* first rcv Message belonging to CPU */ + Pkt *rp[Nrrb]; /* receive buffers */ + int inpackets; + + Rendez tr; /* rendezvous for an output buffer */ + QLock tlock; /* semaphore on tc */ + ushort tl; /* first xmt Message belonging to Lance */ + ushort tc; /* first xmt Message belonging to CPU */ + Pkt *tp[Ntrb]; /* transmit buffers */ + int outpackets; + + Ethertype e[Ntypes]; + int debug; + int prdebug; + int kstarted; + Debqueue dq; +} Lance; +static Lance l; + +/* + * mode bits in the lance initialization block + */ +#define PROM 0x8000 +#define INTL 0x40 +#define DRTY 0x20 +#define COLL 0x10 +#define DTCR 0x8 +#define LOOP 0x4 +#define DTX 0x2 +#define DRX 0x1 + +/* + * LANCE CSR0, this is the register we play with most often. We leave + * this register pointed to by l.rap in normal operation. + */ +#define ERR0 0x8000 +#define BABL 0x4000 +#define CERR 0x2000 +#define MISS 0x1000 +#define MERR 0x800 +#define RINT 0x400 +#define TINT 0x200 +#define IDON 0x100 +#define INTR 0x80 +#define INEA 0x40 +#define RXON 0x20 +#define TXON 0x10 +#define TDMD 0x8 +#define STOP 0x4 +#define STRT 0x2 +#define INIT 0x1 + +/* + * LANCE CSR3 + */ +#define BSWP 0x4 +#define ACON 0x2 +#define BCON 0x1 + +/* + * flag bits from a buffer descriptor in the rcv/xmt rings + */ +#define OWN 0x8000 /* 1 means that the buffer can be used by the chip */ +#define ERR 0x4000 /* error summary, the OR of all error bits */ +#define FRAM 0x2000 /* CRC error and incoming packet not a multiple of 8 bits */ +#define OFLO 0x1000 /* (receive) lost some of the packet */ +#define MORE 0x1000 /* (transmit) more than 1 retry to send the packet */ +#define CRC 0x800 /* (receive) crc error reading packet */ +#define ONE 0x800 /* (transmit) one retry to transmit the packet */ +#define BUF 0x400 /* (receive) out of buffers while reading a packet */ +#define DEF 0x400 /* (transmit) deffered while transmitting packet */ +#define STP 0x200 /* start of packet */ +#define ENP 0x100 /* end of packet */ + +/* + * cntflags bits from a buffer descriptor in the rcv/xmt rings + */ +#define BUFF 0x8000 /* buffer error (host screwed up?) */ +#define UFLO 0x4000 /* underflow from memory */ +#define LCOL 0x1000 /* late collision (ether too long?) */ +#define LCAR 0x800 /* loss of carrier (ether broken?) */ +#define RTRY 0x400 /* couldn't transmit (bad station on ether?) */ +#define TTDR 0x3FF /* time domain reflectometer */ + +/* + * predeclared + */ +void lancekproc(void *); + +/* + * print a packet preceded by a message + */ +printpacket(char *tag, Pkt *p, int len) +{ + print("%s: %d d(%.2ux%.2ux%.2ux%.2ux%.2ux%.2ux)s(%.2ux%.2ux%.2ux%.2ux%.2ux%.2ux)t(%ux %ux)d(%.2ux%.2ux%.2ux%.2ux%.2ux%.2ux%.2ux%.2ux%.2ux%.2ux%.2ux%.2ux)\n", + tag, len, + p->d[0], p->d[1], p->d[2], p->d[3], p->d[4], p->d[5], + p->s[0], p->s[1], p->s[2], p->s[3], p->s[4], p->s[5], p->type[0], p->type[1], + p->data[0], p->data[1], p->data[2], p->data[3], p->data[4], p->data[5], + p->data[6], p->data[7], p->data[8], p->data[9], p->data[10], p->data[11]); +} + +/* + * save a message in a circular queue for later debugging + */ +void +lancedebq(char *tag, Pkt *p, int len) +{ + lock(&l.dq); + l.dq.tag[l.dq.next] = tag; + l.dq.len[l.dq.next] = len; + memcpy(&l.dq.p[l.dq.next], p, sizeof(Dpkt)); + l.dq.next = (l.dq.next+1) % Ndpkt; + unlock(&l.dq); +} + +/* + * copy to/from lance memory till we get it right + */ +void +slowcpy(uchar *to, uchar *from, int n) +{ + memcpy(to, from, n); + while(memcmp(to, from, n)!=0){ + print("lance compare error\n"); + memcpy(to, from, n); + } +} + +/* + * lance stream module definition + */ +static void lanceoput(Queue*, Block*); +static void lancestopen(Queue*, Stream*); +static void lancestclose(Queue*); +static void stagerbuf(void); +Qinfo lanceinfo = { nullput, lanceoput, lancestopen, lancestclose, "lance" }; + +/* + * open a lance line discipline + * + * the lock is to synchronize changing the ethertype with + * sending packets up the stream on interrupts. + */ +void +lancestopen(Queue *q, Stream *s) +{ + Ethertype *et; + + et = &l.e[s->id]; + qlock(et); + RD(q)->ptr = WR(q)->ptr = et; + et->type = 0; + et->q = RD(q); + qunlock(et); +} + +/* + * close lance line discipline + * + * the lock is to synchronize changing the ethertype with + * sending packets up the stream on interrupts. + */ +static void +lancestclose(Queue *q) +{ + Ethertype *et; + + qlock(et); + et = (Ethertype *)(q->ptr); + et->type = 0; + et->q = 0; + qunlock(et); +} + +/* + * assume the q is locked external to this routine + * + * the ``connect'' control message specifyies the type + */ +Proc *lanceout; +static int +isobuf(void *x) +{ + return TSUCC(l.tc) != l.tl; +} +static void +lanceoput(Queue *q, Block *bp ) +{ + int n, len; + Pkt *p; + Msg *m; + + if(bp->type == M_CTL){ + if(streamparse("connect", bp)){ + ((Ethertype *)q->ptr)->type = strtoul((char *)bp->rptr, 0, 0); + } + freeb(bp); + return; + } + + /* + * save up to a delim + */ + if(!putq(q, bp)) + return; + + /* + * only one transmitter at a time + */ + qlock(&l.tlock); + + /* + * Wait till we get an output buffer + */ + if(TSUCC(l.tc) == l.tl){ + print("lance obuf sleep"); + sleep(&l.tr, isobuf, (void *)0); + print("done"); + } + p = l.tp[l.tc]; + + /* + * copy message into lance RAM + */ + len = 0; + while(bp = getq(q)){ + if(sizeof(Pkt) - len >= (n = bp->wptr - bp->rptr)){ + slowcpy(((uchar *)p)+len, bp->rptr, n); + len += n; + } else + print("no room damn it\n"); + if(bp->flags & S_DELIM){ + freeb(bp); + break; + } else + freeb(bp); + } + + /* + * give packet a local address + */ + memcpy(p->s, l.ea, sizeof(l.ea)); + + /* + * pad the packet + */ + if(len < 60) + len = 60; + + lancedebq("out", p, len); + + /* + * set up the ring descriptor and hand to lance + */ + m = &(LANCEMEM->tmr[l.tc]); + m->size = -len; + m->cntflags = 0; + m->laddr = LADDR(l.tp[l.tc]); + m->flags = OWN|STP|ENP|HADDR(l.tp[l.tc]); + l.tc = TSUCC(l.tc); + *l.rdp = INEA|TDMD; /**/ + qunlock(&l.tlock); +} + +/* + * lance directory + */ +enum { + Lchanqid = 1 +}; +Dirtab lancedir[Ntypes]; + + +/* + * stop the lance, disable all ring buffers, and free all staged rcv buffers + */ +void +lancereset(void) +{ + Lancemem *lm=LANCEMEM; + int i; + + /* + * toggle lance's reset line + */ + MODEREG->promenet &= ~1; + MODEREG->promenet |= 1; + + /* + * disable all ring entries + */ + l.tl = l.tc = 0; + for(i = 0; i < Ntrb; i++) + lm->tmr[i].flags = 0; + l.rl = l.rc = 0; + for(i = 0; i < Ntrb; i++) + lm->rmr[i].flags = 0; + + /* + * run through all lance memory to set parity + */ + for(l.lmp=LANCERAM; l.lmp<=LANCEEND; l.lmp++) + *l.lmp = 55; +} + +/* + * Initialize and start the lance. This routine can be called at any time. + * It may be used to restart a dead lance. + */ +static void +lancestart(void) +{ + Lancemem *lm=LANCEMEM; + int i; + Pkt *p; + + lancereset(); + + /* + * create the initialization block + */ + lm->mode = 0; + + /* + * set ether addr from the value in the id prom. + * the id prom has them in reverse order, the init + * structure wants them in byte swapped order + */ + lm->etheraddr[0] = (LANCEID[16]&0xff00)|((LANCEID[20]>>8)&0xff); + lm->etheraddr[1] = (LANCEID[8]&0xff00)|((LANCEID[12]>>8)&0xff); + lm->etheraddr[2] = (LANCEID[0]&0xff00)|((LANCEID[4]>>8)&0xff); + l.ea[0] = LANCEID[20]>>8; + l.ea[1] = LANCEID[16]>>8; + l.ea[2] = LANCEID[12]>>8; + l.ea[3] = LANCEID[8]>>8; + l.ea[4] = LANCEID[4]>>8; + l.ea[5] = LANCEID[0]>>8; + + /* + * ignore multicast addresses + */ + for(i=0; i<4; i++) + lm->multi[i] = 0; + + /* + * set up rcv message ring + */ + p = lm->p; + for(i = 0; i < Nrrb; i++){ + l.rp[i] = p++; + lm->rmr[i].size = -sizeof(Pkt); + lm->rmr[i].cntflags = 0; + lm->rmr[i].laddr = LADDR(l.rp[i]); + lm->rmr[i].flags = HADDR(l.rp[i]); + } + lm->rdralow = LADDR(lm->rmr); + lm->rdrahigh = (LogNrrb<<13)|HADDR(lm->rmr); + + /* + * give the lance all the rcv buffers except one (as a sentinel) + */ + l.rc = Nrrb - 1; + for(i = 0; i < l.rc; i++) + lm->rmr[i].flags |= OWN; + + /* + * set up xmit message ring + */ + for(i = 0; i < Ntrb; i++){ + l.tp[i] = p++; + lm->tmr[i].size = 0; + lm->tmr[i].cntflags = 0; + lm->tmr[i].laddr = LADDR(l.tp[i]); + lm->tmr[i].flags = HADDR(l.tp[i]); + } + lm->tdralow = LADDR(lm->tmr); + lm->tdrahigh = (LogNtrb<<13)|HADDR(lm->tmr); + + /* + * so that we don't have to indirect through constants + */ + l.rap = LANCERAP; + l.rdp = LANCERDP; + + /* + * point lance to the initialization block + */ + *l.rap = 1; + *l.rdp = LADDR(lm); + wbflush(); + *l.rap = 2; + *l.rdp = HADDR(lm); + + /* + * The lance byte swaps the ethernet packet unless we tell it not to + */ + wbflush(); + *l.rap = 3; + *l.rdp = BSWP; + + /* + * initialize lance, turn on interrupts, turn on transmit and rcv. + */ + *l.rap = 0; + *l.rdp = INEA|INIT|STRT; /**/ +} + +/* + * set up the free list and lance directory. + * start the lance. + */ +void +lanceinit(void) +{ + int i; + + /* + * staticly set up types for now + */ + for(i=0; idev = 0; + return c; +} + +Chan* +lanceclone(Chan *c, Chan *nc) +{ + return devclone(c, nc); +} + +/* + * if the name doesn't exist, the name is numeric, and room exists + * in lancedir, create a new entry. + */ +int +lancewalk(Chan *c, char *name) +{ + if(c->qid == CHDIR) + return devwalk(c, name, lancedir, Ntypes, devgen); + else + return devwalk(c, name, 0, 0, streamgen); +} + +void +lancestat(Chan *c, char *dp) +{ + if(c->qid == CHDIR) + devstat(c, dp, lancedir, Ntypes, devgen); + else + devstat(c, dp, 0, 0, streamgen); +} + +/* + * Pass open's of anything except the directory to streamopen + */ +Chan* +lanceopen(Chan *c, int omode) +{ + extern Qinfo nonetinfo; + + if(c->qid == CHDIR){ + if(omode != OREAD) + error(0, Eperm); + }else + streamopen(c, &lanceinfo); + c->mode = openmode(omode); + c->flag |= COPEN; + c->offset = 0; + return c; +} + +void +lancecreate(Chan *c, char *name, int omode, ulong perm) +{ + error(0, Eperm); +} + +void +lanceclose(Chan *c) +{ + /* real closing happens in lancestclose */ + if(c->qid != CHDIR) + streamclose(c); +} + +long +lanceread(Chan *c, void *a, long n) +{ + if(c->qid == CHDIR) + return devdirread(c, a, n, lancedir, Ntypes, devgen); + else + return streamread(c, a, n); +} + +long +lancewrite(Chan *c, void *a, long n) +{ + return streamwrite(c, a, n); +} + +void +lanceremove(Chan *c) +{ + error(0, Eperm); +} + +void +lancewstat(Chan *c, char *dp) +{ + error(0, Eperm); +} + +void +lanceerrstr(Error *e, char *buf) +{ + rooterrstr(e, buf); +} + +void +lanceuserstr(Error *e, char *buf) +{ + consuserstr(e, buf); +} + +/* + * We will: + * (1) Clear interrupt cause in the lance + * (2) service all current events + */ +void +lanceintr(void) +{ + ushort csr; + Lancemem *lm; + + lm = LANCEMEM; + + csr = *l.rdp; + + /* + * turn off the interrupt and any error indicators + */ + *l.rdp = IDON|INEA|TINT|RINT|BABL|CERR|MISS|MERR; + + /* + * see if an error occurred + */ + if(csr & (BABL|MISS|MERR)) + print("lance err %ux\n", csr); + + if(csr & IDON) + l.inited = 1; + + /* + * look for rcv'd packets, just wakeup the input process + */ + if(l.rl!=l.rc && (lm->rmr[l.rl].flags & OWN)==0) + wakeup(&l.rr); + + /* + * look for xmitt'd packets, wake any process waiting for a + * transmit buffer + */ + while(l.tl != l.tc && (lm->tmr[l.tl].flags & OWN) == 0){ + if(lm->tmr[l.tl].flags & ERR) + print("xmt error %ux %ux\n", lm->tmr[l.tl].flags, + lm->tmr[l.tl].cntflags); + l.tl = TSUCC(l.tl); + wakeup(&l.tr); + } +} + +/* + * input process, awakened on each interrupt with rcv buffers filled + */ +static int +isinput(void *arg) +{ + return l.rl!=l.rc && (LANCEMEM->rmr[l.rl].flags & OWN)==0; +} +void +lancekproc(void *arg) +{ + Block *bp; + Lancemem *lm; + Pkt *p; + Ethertype *e; + int t; + Msg *m; + int len; + int i, last; + + lm = LANCEMEM; + + for(;;){ + for(; l.rl!=l.rc && (lm->rmr[l.rl].flags & OWN)==0 ; l.rl=RSUCC(l.rl)){ + l.inpackets++; + m = &(lm->rmr[l.rl]); + if(m->flags & ERR){ + print("rcv error %ux\n", + m->flags&(FRAM|OFLO|CRC|BUFF)); + goto stage; + } + + /* + * See if a queue exists for this packet type. + */ + p = l.rp[l.rl]; + t = (p->type[1]<<8) | p->type[0]; + len = m->cntflags - 4; + lancedebq("in", p, len); + for(e = &l.e[0]; e < &l.e[Ntypes]; e++){ + if(!canqlock(e)) + continue; + if(e->q && t == e->type) + break; + qunlock(e); + } + + /* + * If no match, see if any stream has type -1. + * It matches all packets. + */ + if(e == &l.e[Ntypes]){ + for(e = &l.e[0]; e < &l.e[Ntypes]; e++){ + if(!canqlock(e)) + continue; + if(e->q && e->type == -1) + break; + qunlock(e); + } + } + if(e != &l.e[Ntypes] && e->q->next->len <= Streamhi){ + /* + * The lock on e makes sure the queue is still there. + */ + bp = allocb(len); + slowcpy(bp->rptr, (uchar *)p, len); + bp->wptr += len; + bp->flags |= S_DELIM; + PUTNEXT(e->q, bp); + qunlock(e); + } + +stage: + /* + * stage the next input buffer + */ + m = &(lm->rmr[l.rc]); + m->size = -sizeof(Pkt); + m->cntflags = 0; + m->laddr = LADDR(l.rp[l.rc]); + m->flags = OWN|HADDR(l.rp[l.rc]); + l.rc = RSUCC(l.rc); + } + if(l.prdebug){ + lock(&l.dq); + i = l.dq.next; + do { + if(l.dq.tag[i]) + printpacket(l.dq.tag[i], (Pkt *)&l.dq.p[i], + l.dq.len[i]); + i = (i+1) % Ndpkt; + } while(i != l.dq.next); + unlock(&l.dq); + l.prdebug = 0; + } + sleep(&l.rr, isinput, 0); + } +} + +void +lanceparity(void) +{ + print("lance DRAM parity error lmp=%ux\n", l.lmp); + MODEREG->promenet &= ~4; + MODEREG->promenet |= 4; +} + +void +LANCEDEBUG() +{ + l.debug ^= 1; +} + +/* + * print the debug queue + */ +void +LANCEPRDEBQ() +{ + l.prdebug = 1; + wakeup(&l.rr); +} diff --git a/port/devmnt.c b/port/devmnt.c new file mode 100644 index 0000000000000000000000000000000000000000..867f76f48e9c0f20f790750d8755df44825cb019 --- /dev/null +++ b/port/devmnt.c @@ -0,0 +1,608 @@ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "errno.h" + +#include "devtab.h" + +#include "fcall.h" + +/* + * Easy version: multiple sessions but no intra-session multiplexing, copy the data + */ + +typedef struct Mnt Mnt; +struct Mnt +{ + Ref; /* for number of chans, incl. mntpt but not msg */ + QLock; /* for access */ + Chan *msg; /* for reading and writing messages */ + Chan *mntpt; /* channel in user's name space */ +}; + +#define BUFSIZE (MAXFDATA+500) /* BUG */ +typedef struct Mntbuf Mntbuf; +struct Mntbuf +{ + Mntbuf *next; + char buf[BUFSIZE]; +}; + +struct +{ + Lock; + Mntbuf *free; +}mntbufalloc; + +typedef struct Mnthdr Mnthdr; +struct Mnthdr /* next only meaningful when buffer isn't being used */ +{ + Mnthdr *next; + Fcall thdr; + Fcall rhdr; +}; + +struct +{ + Lock; + Mnthdr *free; +}mnthdralloc; + +Mnt *mnt; +void mntxmit(Mnt*, Mnthdr*); + +Mntbuf* +mballoc(void) +{ + Mntbuf *mb; + +loop: + lock(&mntbufalloc); + if(mb = mntbufalloc.free){ /* assign = */ + mntbufalloc.free = mb->next; + unlock(&mntbufalloc); + return mb; + } + unlock(&mntbufalloc); + print("no mntbufs\n"); + if(u == 0) + panic("mballoc"); + u->p->state = Wakeme; + alarm(1000, wakeme, u->p); + sched(); + goto loop; +} + +void +mbfree(Mntbuf *mb) +{ + lock(&mntbufalloc); + mb->next = mntbufalloc.free; + mntbufalloc.free = mb; + unlock(&mntbufalloc); +} + +Mnthdr* +mhalloc(void) +{ + Mnthdr *mh; + +loop: + lock(&mnthdralloc); + if(mh = mnthdralloc.free){ /* assign = */ + mnthdralloc.free = mh->next; + unlock(&mnthdralloc); + return mh; + } + unlock(&mnthdralloc); + print("no mnthdrs\n"); + if(u == 0) + panic("mballoc"); + u->p->state = Wakeme; + alarm(1000, wakeme, u->p); + sched(); + goto loop; +} + +void +mhfree(Mnthdr *mh) +{ + lock(&mnthdralloc); + mh->next = mnthdralloc.free; + mnthdralloc.free = mh; + unlock(&mnthdralloc); +} + +Mnt* +mntdev(int dev, int noerr) +{ + Mnt *m; + + if(dev<0 || conf.nmntdev<=dev){ + if(noerr) + return 0; + panic("mntdev out of range"); + } + m = &mnt[dev]; + if(m->msg == 0){ + if(noerr) + return 0; + error(0, Eshutdown); + } + return m; +} + +void +mntreset(void) +{ + int i; + Mntbuf *mb; + Mnthdr *mh; + + mnt = ialloc(conf.nmntdev*sizeof(Mnt), 0); + + mb = ialloc(conf.nmntbuf*sizeof(Mntbuf), 0); + for(i=0; iref == 0) + goto Found; + unlock(m); + } + error(0, Enomntdev); + Found: + m->ref = 1; + unlock(m); + c = devattach('M', spec); + c->dev = m - mnt; + m->mntpt = c; + cm = bogus.chan; + m->msg = cm; + incref(cm); + mh = mhalloc(); + if(waserror()){ + mhfree(mh); + close(c); + nexterror(); + } + mh->thdr.type = Tattach; + mh->thdr.fid = c->fid; + memcpy(mh->thdr.uname, u->p->pgrp->user, NAMELEN); + strcpy(mh->thdr.aname, spec); + mntxmit(m, mh); + c->qid = mh->rhdr.qid; + mhfree(mh); + poperror(); + return c; +} + +Chan* +mntclone(Chan *c, Chan *nc) +{ + Mnt *m; + Mnthdr *mh; + int new; + + new = 0; + if(nc == 0){ + nc = newchan(); + new = 1; + if(waserror()){ + close(nc); + nexterror(); + } + } + m = mntdev(c->dev, 0); + mh = mhalloc(); + if(waserror()){ + mhfree(mh); + nexterror(); + } + mh->thdr.type = Tclone; + mh->thdr.fid = c->fid; + mh->thdr.newfid = nc->fid; + mntxmit(m, mh); + nc->type = c->type; + nc->dev = c->dev; + nc->qid = c->qid; + nc->mode = c->mode; + nc->flag = c->flag; + nc->offset = c->offset; + nc->mnt = c->mnt; + if(new) + poperror(); + mhfree(mh); + poperror(); + incref(m); + return nc; +} + +int +mntwalk(Chan *c, char *name) +{ + Mnt *m; + Mnthdr *mh; + int found; + + found = 1; + m = mntdev(c->dev, 0); + mh = mhalloc(); + mh->thdr.type = Twalk; + mh->thdr.fid = c->fid; + strcpy(mh->thdr.name, name); + if(waserror()){ /* BUG: can check type of error? */ + found = 0; + goto Out; + } + mntxmit(m, mh); + c->qid = mh->rhdr.qid; + poperror(); + Out: + mhfree(mh); + return found; +} + +void +mntstat(Chan *c, char *dp) +{ + Mnt *m; + Mnthdr *mh; + + m = mntdev(c->dev, 0); + mh = mhalloc(); + if(waserror()){ + mhfree(mh); + nexterror(); + } + mh->thdr.type = Tstat; + mh->thdr.fid = c->fid; + mntxmit(m, mh); + memcpy(dp, mh->rhdr.stat, DIRLEN); + dp[DIRLEN-4] = devchar[c->type]; + dp[DIRLEN-3] = 0; + dp[DIRLEN-2] = c->dev; + dp[DIRLEN-1] = c->dev>>8; + mhfree(mh); + poperror(); +} + +Chan* +mntopen(Chan *c, int omode) +{ + Mnt *m; + Mnthdr *mh; + + m = mntdev(c->dev, 0); + mh = mhalloc(); + if(waserror()){ + mhfree(mh); + nexterror(); + } + mh->thdr.type = Topen; + mh->thdr.fid = c->fid; + mh->thdr.mode = omode; + mntxmit(m, mh); + c->qid = mh->rhdr.qid; + mhfree(mh); + poperror(); + c->offset = 0; + c->mode = openmode(omode); + c->flag |= COPEN; + return c; +} + +void +mntcreate(Chan *c, char *name, int omode, ulong perm) +{ + Mnt *m; + Mnthdr *mh; + + m = mntdev(c->dev, 0); + mh = mhalloc(); + if(waserror()){ + mhfree(mh); + nexterror(); + } + mh->thdr.type = Tcreate; + mh->thdr.fid = c->fid; + strcpy(mh->thdr.name, name); + mh->thdr.mode = omode; + mh->thdr.perm = perm; + mntxmit(m, mh); + c->qid = mh->rhdr.qid; + mhfree(mh); + poperror(); + c->flag |= COPEN; + c->mode = openmode(omode); + c->qid = mh->rhdr.qid; +} + +void +mntclose(Chan *c) +{ + Mnt *m; + Mnthdr *mh; + + m = mntdev(c->dev, 0); + mh = mhalloc(); + if(waserror()){ + mhfree(mh); + nexterror(); + } + mh->thdr.type = Tclunk; + mh->thdr.fid = c->fid; + mntxmit(m, mh); + mhfree(mh); + if(c == m->mntpt) + m->mntpt = 0; + if(decref(m) == 0){ /* BUG: need to hang up all pending i/o */ + qlock(m); + close(m->msg); + m->msg = 0; + qunlock(m); + } + poperror(); +} + +long +mntreadwrite(Chan *c, void *vbuf, long n, int type) +{ + Mnt *m; + Mnthdr *mh; + long nt, nr, count, offset; + char *buf; + + buf = vbuf; + count = 0; + offset = c->offset; + m = mntdev(c->dev, 0); + mh = mhalloc(); + if(waserror()){ + mhfree(mh); + nexterror(); + } + mh->thdr.type = type; + mh->thdr.fid = c->fid; + Loop: + nt = n; + if(nt > MAXFDATA) + nt = MAXFDATA; + mh->thdr.offset = offset; + mh->thdr.count = nt; + mh->thdr.data = buf; + mntxmit(m, mh); + nr = mh->rhdr.count; + offset += nr; + count += nr; + buf += nr; + n -= nr; + if(n && nr==nt) + goto Loop; + mhfree(mh); + poperror(); + return count; +} + +long +mntread(Chan *c, void *buf, long n) +{ + long i; + uchar *b; + + n = mntreadwrite(c, buf, n, Tread); + if(c->qid & CHDIR){ + b = (uchar*)buf; + for(i=n-DIRLEN; i>=0; i-=DIRLEN){ + b[DIRLEN-4] = devchar[c->type]; + b[DIRLEN-3] = 0; + b[DIRLEN-2] = c->dev; + b[DIRLEN-1] = c->dev>>8; + b += DIRLEN; + } + } + return n; +} + +long +mntwrite(Chan *c, void *buf, long n) +{ + return mntreadwrite(c, buf, n, Twrite); +} + +void +mntremove(Chan *c) +{ + Mnt *m; + Mnthdr *mh; + + m = mntdev(c->dev, 0); + mh = mhalloc(); + if(waserror()){ + mhfree(mh); + nexterror(); + } + mh->thdr.type = Tremove; + mh->thdr.fid = c->fid; + mntxmit(m, mh); + mhfree(mh); + poperror(); +} + +void +mntwstat(Chan *c, char *dp) +{ + Mnt *m; + Mnthdr *mh; + + m = mntdev(c->dev, 0); + mh = mhalloc(); + if(waserror()){ + mhfree(mh); + nexterror(); + } + mh->thdr.type = Twstat; + mh->thdr.fid = c->fid; + memcpy(mh->thdr.stat, dp, DIRLEN); + mntxmit(m, mh); + mhfree(mh); + poperror(); +} + +void +mnterrstr(Error *e, char *buf) +{ + Mnt *m; + Mnthdr *mh; + char *def="mounted device shut down"; + + m = mntdev(e->dev, 1); + if(m == 0){ + strcpy(buf, def); + return; + } + mh = mhalloc(); + if(waserror()){ + strcpy(buf, def); + mhfree(mh); + nexterror(); + } + mh->thdr.type = Terrstr; + mh->thdr.fid = 0; + mh->thdr.err = e->code; + mntxmit(m, mh); + strcpy(buf, (char*)mh->rhdr.ename); + mhfree(mh); + poperror(); +} + +void +mntuserstr(Error *e, char *buf) +{ + Mnt *m; + Mnthdr *mh; + char *def="mounted device shut down"; + + m = mntdev(e->dev, 1); + if(m == 0){ + strcpy(buf, def); + return; + } + mh = mhalloc(); + if(waserror()){ + strcpy(buf, def); + mhfree(mh); + nexterror(); + } + mh->thdr.type = Tuserstr; + mh->thdr.fid = 0; + mh->thdr.uid = e->code; + mntxmit(m, mh); + strcpy(buf, (char*)mh->rhdr.uname); + mhfree(mh); + poperror(); +} + +void +mntxmit(Mnt *m, Mnthdr *mh) +{ + ulong n; + Mntbuf *mbr, *mbw; + Chan *mntpt; + + mbr = mballoc(); + mbw = mballoc(); + if(waserror()){ + mbfree(mbr); + mbfree(mbw); + nexterror(); + } + n = convS2M(&mh->thdr, mbw->buf); + qlock(m); + if(m->msg == 0){ + qunlock(m); + error(0, Eshutdown); + } + qlock(m->msg); + if(waserror()){ + qunlock(m); + qunlock(m->msg); + nexterror(); + } + if((*devtab[m->msg->type].write)(m->msg, mbw->buf, n) != n){ + pprint("short write in mntxmit\n"); + error(0, Egreg); + } + + /* + * Read response + */ + n = (*devtab[m->msg->type].read)(m->msg, mbr->buf, BUFSIZE); + qunlock(m); + qunlock(m->msg); + poperror(); + + if(convM2S(mbr->buf, &mh->rhdr, n) == 0){ + pprint("format error in mntxmit\n"); + error(0, Egreg); + } + + /* + * Various checks + */ + if(mh->rhdr.type != mh->thdr.type+1){ + pprint("type mismatch %d %d\n", mh->rhdr.type, mh->thdr.type+1); + error(0, Egreg); + } + if(mh->rhdr.fid != mh->thdr.fid){ + pprint("fid mismatch %d %d type %d\n", mh->rhdr.fid, mh->thdr.fid, mh->rhdr.type); + error(0, Egreg); + } + if(mh->rhdr.err){ + mntpt = m->mntpt; /* unsafe, but Errors are unsafe anyway */ + if(mntpt) + error(mntpt, mh->rhdr.err); + error(0, Eshutdown); + } + /* + * Copy out on read + */ + if(mh->thdr.type == Tread) + memcpy(mh->thdr.data, mh->rhdr.data, mh->rhdr.count); + mbfree(mbr); + mbfree(mbw); + poperror(); +} diff --git a/port/devpipe.c b/port/devpipe.c new file mode 100644 index 0000000000000000000000000000000000000000..25982e151c47603956c0c187a7c5c3aa51c778ce --- /dev/null +++ b/port/devpipe.c @@ -0,0 +1,218 @@ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "errno.h" + +#include "devtab.h" +#include "fcall.h" + +static void pipeiput(Queue*, Block*); +static void pipeoput(Queue*, Block*); +static void pipestclose(Queue *); +Qinfo pipeinfo = { pipeiput, pipeoput, 0, pipestclose, "process" }; + +void +pipeinit(void) +{ +} + +void +pipereset(void) +{ +} + +/* + * allocate both streams + * + * a subsequent clone will get them the second stream + */ +Chan* +pipeattach(char *spec) +{ + Chan *c; + /* + * make the first stream + */ + c = devattach('|', spec); + c->qid = STREAMQID(0, Sdataqid); + streamnew(c, &pipeinfo); + return c; +} + +Chan* +pipeclone(Chan *c, Chan *nc) +{ + /* + * make the second stream + */ + nc = devclone(c, nc); + if(waserror()){ + close(nc); + nexterror(); + } + nc->qid = STREAMQID(1, Sdataqid); + streamnew(nc, &pipeinfo); + poperror(); + + /* + * attach it to the first + */ + c->stream->devq->other->next = nc->stream->devq; + nc->stream->devq->other->next = c->stream->devq; + return nc; +} + +int +pipewalk(Chan *c, char *name) +{ + print("pipewalk\n"); + error(0, Egreg); +} + +void +pipestat(Chan *c, char *db) +{ + Dir dir; + + devdir(c, c->qid, "pipe", 0, 0, &dir); + convD2M(&dir, db); +} + +Chan * +pipeopen(Chan *c, int omode) +{ + c->mode = omode; + c->flag |= COPEN; + c->offset = 0; + return c; +} + +void +pipecreate(Chan *c, char *name, int omode, ulong perm) +{ + print("pipecreate\n"); + error(0, Egreg); +} + +void +piperemove(Chan *c) +{ + print("piperemove\n"); + error(0, Egreg); +} + +void +pipewstat(Chan *c, char *db) +{ + print("pipewstat\n"); + error(0, Egreg); +} + +void +pipeclose(Chan *c) +{ + streamclose(c); +} + +long +piperead(Chan *c, void *va, long n) +{ + return streamread(c, va, n); +} + +long +pipewrite(Chan *c, void *va, long n) +{ + if(waserror()){ + postnote(u->p, 1, "sys: write on closed pipe", NExit); + error(0, Egreg); + } + return streamwrite(c, va, n); +} + +void +pipeuserstr(Error *e, char *buf) +{ + consuserstr(e, buf); +} + +void +pipeerrstr(Error *e, char *buf) +{ + rooterrstr(e, buf); +} + +/* + * stream stuff + */ +/* + * send a block up stream to the process. + * sleep untill there's room upstream. + */ +static void +pipeiput(Queue *q, Block *bp) +{ + flowctl(q); + PUTNEXT(q, bp); +} + +/* + * send the block to the other side without letting the connection + * disappear in mid put. + */ +static void +pipeoput(Queue *q, Block *bp) +{ + lock(q); + if(q->next) + pipeiput(q->next, bp); + unlock(q); +} + +/* + * send a hangup and disconnect the streams + */ +static void +pipestclose(Queue *q) +{ + Block *bp; + + /* + * point to the bit-bucket and let any in-progress + * write's finish. + */ + q->put = nullput; + wakeup(&q->r); + + /* + * send a hangup + */ + q = q->other; + lock(q); + if(q->next){ + bp = allocb(0); + bp->type = M_HANGUP; + pipeiput(q->next, bp); + } + unlock(q); + + /* + * disconnect (possible livelock?) + */ + for(;;){ + lock(q); + if(q->next){ + if(!canlock(q->next->other)){ + unlock(q); + continue; + } + q->next->other->next = 0; + unlock(q->next->other); + q->next = 0; + } + unlock(q); + break; + } +} diff --git a/port/devproc.c b/port/devproc.c new file mode 100644 index 0000000000000000000000000000000000000000..d444aa1a92fa7fe2ae05081b5f823e8ed2097a60 --- /dev/null +++ b/port/devproc.c @@ -0,0 +1,380 @@ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "errno.h" + +#include "devtab.h" + +enum{ + Qdir, + Qctl, + Qmem, + Qnote, + Qproc, + Qstatus, + Qtext, +}; + +Dirtab procdir[]={ + "ctl", Qctl, 0, 0600, + "mem", Qmem, 0, 0600, + "note", Qnote, 0, 0600, + "proc", Qproc, sizeof(Proc), 0600, + "status", Qstatus, NAMELEN+12+6*12, 0600, + "text", Qtext, 0, 0600, +}; + +/* + * Qids are, from bottom to top: + * 4 bits of file type (qids above) + * 12 bits of process slot number + 1 + * 15 bits of pid, for consistency checking + */ +#define NPROC (sizeof procdir/sizeof(Dirtab)) +#define QSHIFT 4 /* location in qid of proc slot # */ +#define PIDSHIFT 16 /* location in qid of pid */ +#define PIDMASK 0x7FFF /* low bits of pid used in qid */ +#define QID(q) (((q)&0x0000000F)>>0) +#define SLOT(q) ((((q)&0x0000FFF0)>>QSHIFT)-1) +#define PID(q) (((q)&0x7FFF0000)>>PIDSHIFT) + +int +procgen(Chan *c, Dirtab *tab, int ntab, int s, Dir *dp) +{ + Proc *p; + char buf[NAMELEN]; + ulong pid; + + if(c->qid == CHDIR){ + if(s >= conf.nproc) + return -1; + p = proctab(s); + pid = p->pid; + if(pid == 0) + return 0; + sprint(buf, "%d", pid); + devdir(c, CHDIR|(pid<= NPROC) + return -1; + if(tab) + panic("procgen"); + tab = &procdir[s]; + devdir(c, (~CHDIR)&(c->qid|tab->qid), tab->name, tab->length, tab->perm, dp); + return 1; +} + +void +procinit(void) +{ + if(conf.nproc >= (1<<(16-QSHIFT))-1) + print("warning: too many procs for devproc\n"); +} + +void +procreset(void) +{ +} + +Chan* +procattach(char *spec) +{ + return devattach('p', spec); +} + +Chan* +procclone(Chan *c, Chan *nc) +{ + return devclone(c, nc); +} + +int +procwalk(Chan *c, char *name) +{ + return devwalk(c, name, 0, 0, procgen); +} + +void +procstat(Chan *c, char *db) +{ + devstat(c, db, 0, 0, procgen); +} + +Chan * +procopen(Chan *c, int omode) +{ + Proc *p; + Orig *o; + Chan *tc; + + p = proctab(SLOT(c->qid)); + if((p->pid&PIDMASK) != PID(c->qid)) + Died: + error(0, Eprocdied); + omode = openmode(omode); + + switch(QID(c->qid)){ + case Qtext: + o = p->seg[TSEG].o; + if(o==0 || p->state==Dead) + goto Died; + tc = o->chan; + if(tc == 0) + goto Died; + if(incref(tc) == 0){ + Close: + close(tc); + goto Died; + } + if(!(tc->flag&COPEN) || tc->mode!=OREAD) + goto Close; + if((p->pid&PIDMASK) != PID(c->qid)) + goto Close; + qlock(tc); + tc->offset = 0; + qunlock(tc); + return tc; + case Qctl: + case Qnote: + break; + case Qdir: + case Qmem: + case Qproc: + case Qstatus: + if(omode!=OREAD) + error(0, Eperm); + break; + default: + pprint("unknown qid in devopen\n"); + error(0, Egreg); + } + /* + * Affix pid to qid + */ + if(p->state != Dead) + c->qid |= (p->pid&PIDMASK)<mode = omode; + c->flag |= COPEN; + c->offset = 0; + return c; +} + +void +proccreate(Chan *c, char *name, int omode, ulong perm) +{ + error(0, Eperm); +} + +void +procremove(Chan *c) +{ + error(0, Eperm); +} + +void +procwstat(Chan *c, char *db) +{ + error(0, Eperm); +} + +void +procclose(Chan * c) +{ +} + +long +procread(Chan *c, void *va, long n) +{ + char *a = va, *b; + char statbuf[2*NAMELEN+12+6*12]; + Proc *p; + Seg *s; + Orig *o; + Page *pg; + int i; + long l; + long pid; + User *up; + + if(c->qid & CHDIR) + return devdirread(c, a, n, 0, 0, procgen); + + /* + * BUG: should lock(&p->debug)? + */ + p = proctab(SLOT(c->qid)); + if((p->pid&PIDMASK) != PID(c->qid)) + error(0, Eprocdied); + + switch(QID(c->qid)){ + case Qmem: + /* + * One page at a time + */ + if(((c->offset+n)&~(BY2PG-1)) != (c->offset&~(BY2PG-1))) + n = BY2PG - (c->offset&(BY2PG-1)); + s = seg(p, c->offset); + if(s){ + o = s->o; + if(o == 0) + error(0, Eprocdied); + lock(o); + if(s->o!=o || (p->pid&PIDMASK)!=PID(c->qid)){ + unlock(o); + error(0, Eprocdied); + } + if(seg(p, c->offset) != s){ + unlock(o); + error(0, Egreg); + } + pg = o->pte[(c->offset-o->va)>>PGSHIFT].page; + unlock(o); + if(pg == 0){ + pprint("nonresident page (complain to rob)\n"); + memset(a, 0, n); + }else{ + b = (char*)(pg->pa|KZERO); + memcpy(a, b+(c->offset&(BY2PG-1)), n); + } + return n; + } + + /* u area */ + if(c->offset>=USERADDR && c->offset<=USERADDR+BY2PG){ + if(c->offset+n > USERADDR+BY2PG) + n = USERADDR+BY2PG - c->offset; + pg = p->upage; + if(pg==0 || (p->pid&PIDMASK)!=PID(c->qid)) + error(0, Eprocdied); + b = (char*)(pg->pa|KZERO); + memcpy(a, b+(c->offset-USERADDR), n); + return n; + } + + /* kernel memory. BUG: shouldn't be so easygoing. BUG: mem mapping? */ + if(c->offset>=KZERO && c->offsetoffset+n > KZERO+conf.npage*BY2PG) + n = KZERO+conf.npage*BY2PG - c->offset; + memcpy(a, (char*)c->offset, n); + return n; + } + return 0; + break; + + case Qnote: + lock(&p->debug); + if(waserror()){ + unlock(&p->debug); + nexterror(); + } + if((p->pid&PIDMASK) != PID(c->qid)) + error(0, Eprocdied); + up = (User*)(p->upage->pa|KZERO); + if(up->p != p){ + pprint("note read u/p mismatch"); + error(0, Egreg); + } + if(n < ERRLEN) + error(0, Etoosmall); + if(up->nnote == 0) + n = 0; + else{ + memcpy(va, up->note[0].msg, ERRLEN); + up->nnote--; + memcpy(&up->note[0], &up->note[1], up->nnote*sizeof(Note)); + n = ERRLEN; + } + unlock(&p->debug); + return n; + + case Qproc: + if(c->offset >= sizeof(Proc)) + return 0; + if(c->offset+n > sizeof(Proc)) + n = sizeof(Proc) - c->offset; + memcpy(a, ((char*)p)+c->offset, n); + return n; + + case Qstatus: + if(c->offset >= sizeof statbuf) + return 0; + if(c->offset+n > sizeof statbuf) + n = sizeof statbuf - c->offset; + sprint(statbuf, "%-27s %-27s %-11s ", p->text, p->pgrp->user, statename[p->state]); + for(i=0; i<6; i++){ + l = p->time[i]; + if(i == TReal) + l = MACHP(0)->ticks - l; + l *= MS2HZ; + readnum(0, statbuf+2*NAMELEN+12+NUMSIZE*i, NUMSIZE, l, NUMSIZE); + } + memcpy(a, statbuf+c->offset, n); + return n; + } + error(0, Egreg); +} + + +long +procwrite(Chan *c, void *va, long n) +{ + Proc *p; + User *up; + char buf[ERRLEN]; + + if(c->qid & CHDIR) + error(0, Eisdir); + p = proctab(SLOT(c->qid)); + lock(&p->debug); + if(waserror()){ + unlock(&p->debug); + nexterror(); + } + if((p->pid&PIDMASK) != PID(c->qid)) + Died: + error(0, Eprocdied); + + switch(QID(c->qid)){ + case Qctl: + if(p->state==Broken && n>=4 && strncmp(va, "exit", 4)==0) + ready(p); + else + error(0, Ebadctl); + break; + case Qnote: + up = (User*)(p->upage->pa|KZERO); + if(up->p != p){ + pprint("note write u/p mismatch"); + error(0, Egreg); + } + if(n >= ERRLEN-1) + error(0, Etoobig); + if(n>=4 && strncmp(va, "sys:", 4)==0) + error(0, Ebadarg); + memcpy(buf, va, n); + buf[n] = 0; + if(!postnote(p, 0, buf, NUser)) + error(0, Enonote); + break; + default: + pprint("unknown qid in procwrite\n"); + error(0, Egreg); + } + unlock(&p->debug); + return n; +} + +void +procuserstr(Error *e, char *buf) +{ + consuserstr(e, buf); +} + +void +procerrstr(Error *e, char *buf) +{ + rooterrstr(e, buf); +} diff --git a/port/devroot.c b/port/devroot.c new file mode 100644 index 0000000000000000000000000000000000000000..ed9de4bbf8af8c554f09355e771da3ed228b2d92 --- /dev/null +++ b/port/devroot.c @@ -0,0 +1,140 @@ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "errno.h" +#include "devtab.h" + +enum{ + Qdir, + Qbin, + Qboot, + Qdev, + Qenv, + Qproc, +}; + +Dirtab rootdir[]={ + "bin", Qbin|CHDIR, 0, 0700, + "boot", Qboot, 0, 0700, + "dev", Qdev|CHDIR, 0, 0700, + "env", Qenv|CHDIR, 0, 0700, + "proc", Qproc|CHDIR, 0, 0700, +}; + +#define NROOT (sizeof rootdir/sizeof(Dirtab)) + +void +rootreset(void) +{ +} + +void +rootinit(void) +{ +} + +Chan* +rootattach(char *spec) +{ + return devattach('/', spec); +} + +Chan* +rootclone(Chan *c, Chan *nc) +{ + return devclone(c, nc); +} + +int +rootwalk(Chan *c, char *name) +{ + return devwalk(c, name, rootdir, NROOT, devgen); +} + +void +rootstat(Chan *c, char *dp) +{ + devstat(c, dp, rootdir, NROOT, devgen); +} + +Chan* +rootopen(Chan *c, int omode) +{ + return devopen(c, omode, rootdir, NROOT, devgen); +} + +void +rootcreate(Chan *c, char *name, int omode, ulong perm) +{ + error(0, Eperm); +} + +/* + * sysremove() knows this is a nop + */ +void +rootclose(Chan *c) +{ +} + +#include "boot.h" + +long +rootread(Chan *c, void *buf, long n) +{ + + switch(c->qid & ~CHDIR){ + case Qdir: + return devdirread(c, buf, n, rootdir, NROOT, devgen); + + case Qboot: /* boot */ + if(c->offset >= sizeof bootcode) + return 0; + if(c->offset+n > sizeof bootcode) + n = sizeof bootcode - c->offset; + memcpy(buf, ((char*)bootcode)+c->offset, n); + return n; + + case Qdev: + return 0; + } + error(0, Egreg); + return 0; +} + +long +rootwrite(Chan *c, void *buf, long n) +{ + error(0, Egreg); +} + +void +rootremove(Chan *c) +{ + error(0, Eperm); +} + +void +rootwstat(Chan *c, char *dp) +{ + error(0, Eperm); +} + +void +rootuserstr(Error *e, char *buf) +{ + consuserstr(e, buf); +} + +#include "errstr.h" + +void +rooterrstr(Error *e, char *buf) +{ + if(e->code<0 || e->code>=sizeof errstrtab/sizeof(char*)) + strcpy(buf, "no such error"); + else + strcpy(buf, errstrtab[e->code]); +} diff --git a/port/devsrv.c b/port/devsrv.c new file mode 100644 index 0000000000000000000000000000000000000000..3a96b82499f77a20dc6b176bd45865f481e86716 --- /dev/null +++ b/port/devsrv.c @@ -0,0 +1,203 @@ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "errno.h" + +#include "devtab.h" + +typedef struct Srv Srv; +struct Srv{ + Lock; + char *name; + Chan **chan; +}srv; + +int +srvgen(Chan *c, Dirtab *tab, int ntab, int s, Dir *dp) +{ + + if(s >= conf.nsrv) + return -1; + if(srv.chan[s] == 0) + return 0; + devdir(c, s, &srv.name[s*NAMELEN], 0, 0666, dp); + return 1; +} + +void +srvinit(void) +{ +} + +void +srvreset(void) +{ + srv.chan = ialloc(conf.nsrv*sizeof(Chan*), 0); + srv.name = ialloc(conf.nsrv*NAMELEN, 0); +} + +Chan * +srvattach(char *spec) +{ + return devattach('s', spec); +} + +Chan * +srvclone(Chan *c, Chan *nc) +{ + return devclone(c, nc); +} + +int +srvwalk(Chan *c, char *name) +{ + return devwalk(c, name, (Dirtab *)0, 0, srvgen); +} + +void +srvstat(Chan *c, char *db) +{ + devstat(c, db, (Dirtab *)0, 0L, srvgen); +} + +Chan * +srvopen(Chan *c, int omode) +{ + Chan *f; + + if(c->qid == CHDIR){ + if(omode != OREAD) + error(0, Eisdir); + c->mode = omode; + c->flag |= COPEN; + c->offset = 0; + return c; + } + lock(&srv); + if(waserror()){ + unlock(&srv); + nexterror(); + } + f = srv.chan[c->qid]; + if(f == 0) + error(0, Eshutdown); + if(omode&OTRUNC) + error(0, Eperm); + if(omode!=f->mode && f->mode!=ORDWR) + error(0, Eperm); + close(c); + incref(f); + unlock(&srv); + poperror(); + return f; +} + +void +srvcreate(Chan *c, char *name, int omode, ulong perm) +{ + int j, i; + + if(omode != OWRITE) + error(0, Eperm); + lock(&srv); + if(waserror()){ + unlock(&srv); + nexterror(); + } + j = -1; + for(i=0; iqid = j; + c->flag |= COPEN; + c->mode = OWRITE; +} + +void +srvremove(Chan *c) +{ + Chan *f; + + if(c->qid == CHDIR) + error(0, Eperm); + lock(&srv); + if(waserror()){ + unlock(&srv); + nexterror(); + } + f = srv.chan[c->qid]; + if(f == 0) + error(0, Eshutdown); + if(strcmp(&srv.name[c->qid*NAMELEN], "boot") == 0) + error(0, Eperm); + srv.chan[c->qid] = 0; + unlock(&srv); + poperror(); + close(f); +} + +void +srvwstat(Chan *c, char *dp) +{ + error(0, Egreg); +} + +void +srvclose(Chan *c) +{ +} + +long +srvread(Chan *c, void *va, long n) +{ + char *a = va; + + if(c->qid != CHDIR) + panic("srvread"); + return devdirread(c, a, n, (Dirtab *)0, 0L, srvgen); +} + +long +srvwrite(Chan *c, void *va, long n) +{ + int i, fd; + char buf[32]; + + i = c->qid; + if(srv.chan[i] != c) /* already been written to */ + error(0, Egreg); + if(n >= sizeof buf) + error(0, Egreg); + memcpy(buf, va, n); /* so we can NUL-terminate */ + buf[n] = 0; + fd = strtoul(buf, 0, 0); + fdtochan(fd, -1); /* error check only */ + srv.chan[i] = u->fd[fd]; + incref(u->fd[fd]); + return n; +} + +void +srverrstr(Error *e, char *buf) +{ + rooterrstr(e, buf); +} + +void +srvuserstr(Error *e, char *buf) +{ + consuserstr(e, buf); +} diff --git a/port/fault.c b/port/fault.c new file mode 100644 index 0000000000000000000000000000000000000000..51bb69b48647c2b5de43153041311bf667b4a978 --- /dev/null +++ b/port/fault.c @@ -0,0 +1,267 @@ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "ureg.h" +#include "errno.h" + +void +fault(Ureg *ur, int user, int code) +{ + ulong addr, mmuvirt, mmuphys, n; + extern char *excname[]; + Seg *s; + PTE *opte, *pte, *npte; + Orig *o; + char *l; + Page *pg; + int zeroed = 0, head = 1; + int i; + + addr = ur->badvaddr; + addr &= ~(BY2PG-1); + + s = seg(u->p, addr); + if(s == 0){ + if(addr>USTKTOP){ + cant: + if(user){ + pprint("user %s badvaddr=0x%lux\n", excname[code], ur->badvaddr); + pprint("status=0x%lux pc=0x%lux sp=0x%lux\n", ur->status, ur->pc, ur->sp); + pexit("Suicide", 0); + } + print("kernel %s badvaddr=0x%lux\n", excname[code], ur->badvaddr); + print("status=0x%lux pc=0x%lux sp=0x%lux\n", ur->status, ur->pc, ur->sp); + u->p->state = MMUing; + dumpregs(ur); + panic("fault"); + } + s = &u->p->seg[SSEG]; + if(s->o==0 || addrmaxva-4*1024*1024 || addr>=s->maxva) + goto cant; + /* grow stack */ + o = s->o; + n = o->npte; + growpte(o, (s->maxva-addr)>>PGSHIFT); + /* stacks grown down, sigh */ + lock(o); + memcpy(o->pte+(o->npte-n), o->pte, n*sizeof(PTE)); + memset(o->pte, 0, (o->npte-n)*sizeof(PTE)); + unlock(o); + s->minva = addr; + o->va = addr; + }else + o = s->o; + if((code==CTLBM || code==CTLBS) && (o->flag&OWRPERM)==0) + goto cant; + lock(o); + opte = &o->pte[(addr-o->va)>>PGSHIFT]; + pte = opte; + if(s->mod){ + while(pte = pte->nextmod) /* assign = */ + if(pte->proc == u->p){ + if(pte->page==0 || pte->page->va!=addr) + panic("bad page %lux", pte->page); + head = 0; + break; + } + if(pte == 0) + pte = opte; + } + if(pte->page == 0){ + if(o->chan==0 || addr>(o->va+(o->maxca-o->minca))){ + /* + * Zero fill page. If we are really doing a copy-on-write + * (e.g. into shared bss) we'll move the page later. + */ + pte->page = newpage(0, o, addr); + o->npage++; + zeroed = 1; + }else{ + /* + * Demand load. Release o because it could take a while. + */ + unlock(o); + n = (o->va+(o->maxca-o->minca)) - addr; + if(n > BY2PG) + n = BY2PG; + pg = newpage(1, o, addr); + qlock(o->chan); + if(waserror()){ + print("demand load i/o error %d\n", u->error.code); + qunlock(o->chan); + pg->o = 0; + pg->ref--; + goto cant; + } + o->chan->offset = (addr-o->va) + o->minca; + l = (char*)(pg->pa|KZERO); + if((*devtab[o->chan->type].read)(o->chan, l, n) != n) + error(0, Eioload); + qunlock(o->chan); + poperror(); + /* BUG: if was first page of bss, move to data */ + if(npte[(addr-s->minva)>>PGSHIFT]; /* could move */ + pte = opte; + if(pte->page == 0){ + pte->page = pg; + o->npage++; + }else{ /* someone beat us to it */ + pg->o = 0; + pg->ref--; + } + } + } + /* + * Copy on reference + */ + if((o->flag & OWRPERM) + && ((head && ((o->flag&OPURE) || o->nproc>1)) + || (!head && pte->page->ref>1))){ + + /* + * Look for the easy way out: are we the last non-modified? + */ + if(head && !(o->flag&OPURE)){ + npte = opte; + for(i=0; npte; i++) + npte = npte->nextmod; + if(i == o->nproc) + goto easy; + } + if(head){ + /* + * Add to mod list + */ + pte = newmod(); + pte->proc = u->p; + pte->page = opte->page; + pte->page->ref++; + o->npage++; + /* + * Link into opte mod list (same va) + */ + pte->nextmod = opte->nextmod; + opte->nextmod = pte; + /* + * Link into proc mod list (increasing va) + */ + npte = s->mod; + if(npte == 0){ + s->mod = pte; + pte->nextva = 0; + }else{ + while(npte->nextva && npte->nextva->page->vanextva; + pte->nextva = npte->nextva; + npte->nextva = pte; + } + head = 0; + } + pg = pte->page; + if(zeroed){ /* move page */ + pg->ref--; + o->npage--; + opte->page = 0; + }else{ /* copy page */ + pte->page = newpage(1, o, addr); + memcpy((void*)(pte->page->pa|KZERO), (void*)(pg->pa|KZERO), BY2PG); + if(pg->ref <= 1) + panic("pg->ref <= 1"); + pg->ref--; + } + easy: + mmuphys = PTEWRITE; + }else{ + mmuphys = 0; + if(o->flag & OWRPERM) + if(o->flag & OPURE){ + if(!head && pte->page->ref==1) + mmuphys = PTEWRITE; + }else + if((head && o->nproc==1) + || (!head && pte->page->ref==1)) + mmuphys = PTEWRITE; + } + mmuvirt = addr; + mmuphys |= pte->page->pa | PTEVALID; + 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){ + print("wrong proc in tail %d %s\n", head, u->p->text); + 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); + putmmu(mmuvirt, mmuphys); +} + +/* + * Called only in a system call + */ +void +validaddr(ulong addr, ulong len, int write) +{ + Seg *s; + + if((long)len < 0) + panic("validaddr len %lux\n", len); + s = seg(u->p, addr); + if(s==0 || addr+len>s->maxva || (write && (s->o->flag&OWRPERM)==0)){ + pprint("invalid address in sys call pc %lux sp %lux\n", ((Ureg*)UREGADDR)->pc, ((Ureg*)UREGADDR)->sp); + postnote(u->p, 1, "bad address", NDebug); + error(0, Ebadarg); + } +} + +void +evenaddr(ulong addr) +{ + if(addr & 3){ + postnote(u->p, 1, "odd address", NDebug); + error(0, Ebadarg); + } +} + +/* + * &s[0] is known to be a valid address. + */ +void* +vmemchr(void *s, int c, int n) +{ + int m; + char *t; + ulong a; + + a = (ulong)s; + m = BY2PG - (a & (BY2PG-1)); + if(m < n){ + t = vmemchr(s, c, m); + if(t) + return t; + if(!(a & KZERO)) + validaddr(a+m, 1, 0); + return vmemchr((void*)(a+m), c, n-m); + } + /* + * All in one page + */ + return memchr(s, c, n); +} + +Seg* +seg(Proc *p, ulong addr) +{ + int i; + Seg *s; + + for(i=0,s=p->seg; io && s->minva<=addr && addrmaxva) + return s; + return 0; +} diff --git a/port/fcall.c b/port/fcall.c new file mode 100644 index 0000000000000000000000000000000000000000..e51e1bf54209e17ab16d4393874cc878d988f175 --- /dev/null +++ b/port/fcall.c @@ -0,0 +1,379 @@ +#include +#include "lib.h" +#include "fcall.h" + +#define CHAR(x) *p++ = f->x +#define SHORT(x) p[0] = f->x; p[1] = f->x>>8; p += 2 +#define LONG(x) p[0] = f->x; p[1] = f->x>>8; p[2] = f->x>>16; p[3] = f->x>>24; p += 4 +#define VLONG(x) p[0] = f->x; p[1] = f->x>>8; p[2] = f->x>>16; p[3] = f->x>>24;\ + p[4] = 0; p[5] = 0; p[6] = 0; p[7] = 0; p += 8 +#define STRING(x,n) memcpy(p, f->x, n); p += n + +int +convS2M(Fcall *f, char *ap) +{ + uchar *p; + + p = (uchar*)ap; + CHAR(type); + switch(f->type) + { + default: + print("bad type: %d\n", f->type); + return 0; + + case Tnop: + case Rnop: + break; + + case Tsession: + CHAR(lang); + break; + + case Tattach: + SHORT(fid); + STRING(uname, sizeof(f->uname)); + STRING(aname, sizeof(f->aname)); + break; + + case Tclone: + SHORT(fid); + SHORT(newfid); + break; + + case Twalk: + case Tremove: + SHORT(fid); + STRING(name, sizeof(f->name)); + break; + + case Topen: + SHORT(fid); + CHAR(mode); + break; + + case Tcreate: + SHORT(fid); + STRING(name, sizeof(f->name)); + LONG(perm); + CHAR(mode); + break; + + case Toread: + case Tread: + SHORT(fid); + VLONG(offset); + SHORT(count); + break; + + case Towrite: + SHORT(fid); + VLONG(offset); + SHORT(count); + STRING(data, f->count); + break; + + case Twrite: + SHORT(fid); + VLONG(offset); + SHORT(count); + p++; + STRING(data, f->count); + break; + + case Tclunk: + case Tstat: + SHORT(fid); + break; + + case Twstat: + SHORT(fid); + STRING(stat, sizeof(f->stat)); + break; + + case Terrstr: + SHORT(fid); + SHORT(err); + break; + + case Tuserstr: + SHORT(fid); + SHORT(uid); + break; +/* + */ + case Rsession: + SHORT(err); + break; + + case Rclone: + case Rclunk: + case Rremove: + case Rwstat: + SHORT(fid); + SHORT(err); + break; + + case Rwalk: + case Rattach: + case Ropen: + case Rcreate: + SHORT(fid); + SHORT(err); + LONG(qid); + break; + + case Roread: + SHORT(fid); + SHORT(err); + SHORT(count); + STRING(data, f->count); + break; + + case Rread: + SHORT(fid); + SHORT(err); + SHORT(count); + p++; + STRING(data, f->count); + break; + + case Rowrite: + case Rwrite: + SHORT(fid); + SHORT(err); + SHORT(count); + break; + + case Rstat: + SHORT(fid); + SHORT(err); + STRING(stat, sizeof(f->stat)); + break; + + case Rerrstr: + SHORT(fid); + SHORT(err); + STRING(ename, sizeof(f->ename)); + break; + + case Ruserstr: + SHORT(fid); + SHORT(err); + STRING(uname, sizeof(f->uname)); + break; + } + return p - (uchar*)ap; +} + +int +convD2M(Dir *f, char *ap) +{ + uchar *p; + + p = (uchar*)ap; + STRING(name, sizeof(f->name)); + LONG(qid); + p += 4; + LONG(mode); + LONG(atime); + LONG(mtime); + VLONG(length); + SHORT(uid); + SHORT(gid); + SHORT(type); + SHORT(dev); + return p - (uchar*)ap; +} + +#undef CHAR +#undef SHORT +#undef LONG +#undef VLONG +#undef STRING + +#define CHAR(x) f->x = *p++ +#define SHORT(x) f->x = (p[0] | (p[1]<<8)); p += 2 +#define LONG(x) f->x = (p[0] | (p[1]<<8) |\ + (p[2]<<16) | (p[3]<<24)); p += 4 +#define VLONG(x) f->x = (p[0] | (p[1]<<8) |\ + (p[2]<<16) | (p[3]<<24)); p += 8 +#define STRING(x,n) memcpy(f->x, p, n); p += n + +int +convM2S(char *ap, Fcall *f, int n) +{ + uchar *p; + + p = (uchar*)ap; + CHAR(type); + switch(f->type) + { + default: + print("bad type: %d\n", f->type); + return 0; + + case Tnop: + case Rnop: + break; + + case Tsession: + CHAR(lang); + break; + + case Tattach: + SHORT(fid); + STRING(uname, sizeof(f->uname)); + STRING(aname, sizeof(f->aname)); + break; + + case Tclone: + SHORT(fid); + SHORT(newfid); + break; + + case Twalk: + case Tremove: + SHORT(fid); + STRING(name, sizeof(f->name)); + break; + + case Topen: + SHORT(fid); + CHAR(mode); + break; + + case Tcreate: + SHORT(fid); + STRING(name, sizeof(f->name)); + LONG(perm); + CHAR(mode); + break; + + case Toread: + case Tread: + SHORT(fid); + VLONG(offset); + SHORT(count); + break; + + case Towrite: + SHORT(fid); + VLONG(offset); + SHORT(count); + f->data = (char*)p; p += f->count; + break; + + case Twrite: + SHORT(fid); + VLONG(offset); + SHORT(count); + p++; + f->data = (char*)p; p += f->count; + break; + + case Tclunk: + case Tstat: + SHORT(fid); + break; + + case Twstat: + SHORT(fid); + STRING(stat, sizeof(f->stat)); + break; + + case Terrstr: + SHORT(fid); + SHORT(err); + break; + + case Tuserstr: + SHORT(fid); + SHORT(uid); + break; + + case Rsession: + SHORT(err); + break; + + case Rclone: + case Rclunk: + case Rremove: + case Rwstat: + SHORT(fid); + SHORT(err); + break; + + case Rwalk: + case Rattach: + case Ropen: + case Rcreate: + SHORT(fid); + SHORT(err); + LONG(qid); + break; + + case Roread: + SHORT(fid); + SHORT(err); + SHORT(count); + f->data = (char*)p; p += f->count; + break; + + case Rread: + SHORT(fid); + SHORT(err); + SHORT(count); + p++; + f->data = (char*)p; p += f->count; + break; + + case Rowrite: + case Rwrite: + SHORT(fid); + SHORT(err); + SHORT(count); + break; + + case Rstat: + SHORT(fid); + SHORT(err); + STRING(stat, sizeof(f->stat)); + break; + + case Rerrstr: + SHORT(fid); + SHORT(err); + STRING(ename, sizeof(f->ename)); + break; + + case Ruserstr: + SHORT(fid); + SHORT(err); + STRING(uname, sizeof(f->uname)); + break; + } + if((uchar*)ap+n == p) + return n; + return 0; +} + +int +convM2D(char *ap, Dir *f) +{ + uchar *p; + + p = (uchar*)ap; + STRING(name, sizeof(f->name)); + LONG(qid); + p += 4; + LONG(mode); + LONG(atime); + LONG(mtime); + VLONG(length); + SHORT(uid); + SHORT(gid); + SHORT(type); + SHORT(dev); + return p - (uchar*)ap; +} diff --git a/port/lib.h b/port/lib.h new file mode 100644 index 0000000000000000000000000000000000000000..441389b966e862cee396bb6a6b37436f05762c3e --- /dev/null +++ b/port/lib.h @@ -0,0 +1,109 @@ +/* + * functions (possibly) linked in, complete, from libc. + */ + +/* + * mem routines + */ +extern void *memccpy(void*, void*, int, long); +extern void *memset(void*, int, long); +extern int memcmp(void*, void*, long); +extern void *memcpy(void*, void*, long); +extern void *memchr(void*, int, long); + +/* + * string routines + */ +extern char *strcat(char*, char*); +extern char *strchr(char*, char); +extern int strcmp(char*, char*); +extern char *strcpy(char*, char*); +extern char *strncat(char*, char*, long); +extern char *strncpy(char*, char*, long); +extern int strncmp(char*, char*, long); +extern long strlen(char*); + +/* + * print routines + */ + +#define FUNSIGN 4 +#define FSHORT 2 +#define FLONG 1 + +typedef struct Op Op; +struct Op +{ + char *p; + char *ep; + void *argp; + int f1; + int f2; + int f3; +}; +extern void strconv(char*, Op*, int, int); +extern int numbconv(Op*, int); +extern char *donprint(char*, char*, char*, void*); +extern int fmtinstall(char, int (*)(Op*)); +extern int sprint(char*, char*, ...); +extern int print(char*, ...); + +/* + * one-of-a-kind + */ +extern long strtol(char*, char**, int); +extern ulong strtoul(char*, char**, int); +extern long end; + +/* + * Syscall data structures + */ + +#define MORDER 0x0003 /* mask for bits defining order of mounting */ +#define MREPL 0x0000 /* mount replaces object */ +#define MBEFORE 0x0001 /* mount goes before others in union directory */ +#define MAFTER 0x0002 /* mount goes after others in union directory */ +#define MCREATE 0x0004 /* permit creation in mounted directory */ +#define MMASK 0x0007 /* all bits on */ + +#define OREAD 0 /* open for read */ +#define OWRITE 1 /* write */ +#define ORDWR 2 /* read and write */ +#define OEXEC 3 /* execute, == read but check execute permission */ +#define OTRUNC 16 /* or'ed in (except for exec), truncate file first */ + +typedef struct Error Error; +typedef struct Dir Dir; +typedef struct Waitmsg Waitmsg; + +struct Error +{ + int type; + int dev; + int code; +}; + +#define ERRLEN 64 +#define DIRLEN 64 +#define NAMELEN 28 +struct Dir +{ + char name[NAMELEN]; + long qid; + long mode; + long atime; + long mtime; + Length; + short uid; + short gid; + short type; + short dev; +}; + +struct Waitmsg +{ + int pid; /* of loved one */ + int status; /* unused; a placeholder */ + ulong time[3]; /* of loved one */ + char msg[ERRLEN]; +}; diff --git a/port/page.c b/port/page.c new file mode 100644 index 0000000000000000000000000000000000000000..8d6bf85a7cc6627f0a426b82b590dde7f5e23fd9 --- /dev/null +++ b/port/page.c @@ -0,0 +1,636 @@ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "ureg.h" + +struct +{ + Lock; + ulong addr; + int active; + Page *page; /* base of Page structures, indexed by phys addr */ + ulong minppn; /* index of first usable page */ + Page *head; /* most recently used */ + Page *tail; /* least recently used */ +}palloc; + +struct +{ + Lock; + Orig *arena; + Orig *free; +}origalloc; + +typedef union PTEA PTEA; +union PTEA{ + PTE; + struct{ + ulong n; /* for growpte */ + Orig *o; /* for growpte */ + PTEA *next; /* for newmod */ + }; +}; + +struct +{ + Lock; + PTEA *arena; + PTEA *free; + PTEA *end; +}ptealloc; + +struct{ + Lock; + PTEA *free; +}modalloc; + +/* + * Called to allocate permanent data structures, before calling pageinit(). + */ +void* +ialloc(ulong n, int align) +{ + ulong p; + + if(palloc.active) + print("ialloc bad\n"); + if(palloc.addr == 0) + palloc.addr = ((ulong)&end)&~KZERO; + if(align){ + palloc.addr += BY2PG-1; + palloc.addr &= ~(BY2PG-1); + } + memset((void*)(palloc.addr|KZERO), 0, n); + p = palloc.addr; + palloc.addr += n; + if(align){ + palloc.addr += BY2PG-1; + palloc.addr &= ~(BY2PG-1); + } + return (void*)(p|KZERO); +} + +void +audit(char *s) +{ + int nf, nb; + Page *p; + +static int here; +do;while(here); +here=1; + + p = palloc.head; + nf=nb=0; + while(p){ +print("%lux %lux %d\n", p->pa, p->va, p->ref); +if(p->o) print("\t%d %lux %c\n", p->o->nproc, p->o->qid, devchar[p->o->type]); +delay(100); + nf++; + p = p->next; + } + p = palloc.tail; + while(p){ + nb++; + p = p->prev; + } + print("%s: nf: %d nb: %d\n", s, nf, nb); + delay(1000); +here=0; +} + +void +pageinit(void) +{ + ulong pa, nb, ppn; + ulong i; + Page *p; + PTEA *pte; + Orig *o; + + ptealloc.arena = ialloc(conf.npte*sizeof(PTEA), 0); + ptealloc.free = ptealloc.arena; + ptealloc.end = ptealloc.arena+conf.npte; + + modalloc.free = ialloc(conf.nmod*sizeof(PTEA), 0); + + pte = modalloc.free; + for(i=0; inext = pte+1; + pte->next = 0; + + origalloc.free = ialloc(conf.norig*sizeof(Orig), 0); + origalloc.arena = origalloc.free; + + o = origalloc.free; + for(i=0; inext = o+1; + o->next = 0; + palloc.active = 1; + + nb = (conf.npage<>PGSHIFT)*sizeof(Page); /* safe overestimate */ + nb &= ~(BY2PG-1); + pa = (conf.npage<> PGSHIFT; /* physical page number of first free page */ + palloc.page = (Page *)((palloc.addr - ppn*sizeof(Page))|KZERO); + /* + * Now palloc.page[ppn] describes first free page + */ + palloc.minppn = ppn; + palloc.addr = ppn<next = p+1; + p->prev = p-1; + p->pa = ppn<prev = 0; + palloc.tail->next = 0; +} + +Page* +newpage(int noclear, Orig *o, ulong va) +{ + Page *p; + Orig *o1; + + if(palloc.active == 0) + print("newpage inactive\n"); +loop: + lock(&palloc); + for(p=palloc.tail; p; p=p->prev){ + if(p->ref == 0) + goto out; +#ifdef asdf + if(p->ref == 1){ /* a pageout daemon should do this */ + o1 = p->o; + if(o1 && o1->nproc==0 && canlock(o1)){ + if(o1->nproc){ + unlock(o1); + continue; + } + print("free %d pages va %lux %lux %c\n", o1->npage, o->va, o1->qid, devchar[o1->type]); + freepage(o1); + /* neworig will free the orig and pte's later */ + unlock(o1); + if(p->ref == 0) + goto out; + print("newpage ref != 0"); + } + } +#endif + } + audit("newpage"); + print("no physical memory\n"); + unlock(&palloc); + if(u == 0) + panic("newpage"); + u->p->state = Wakeme; + alarm(1000, wakeme, u->p); + sched(); + goto loop; + out: + if(p->o){ + print("page in use %lux %lux %lux\n", p->va, p->o, origalloc.arena); + print("%c %lux %lux, %d %d %d\n", devchar[p->o->type], p->o->va, p->o->qid, p->o->flag, p->o->nproc, p->o->npte); + panic("shit"); + } + p->ref = 1; + usepage(p, 0); + unlock(&palloc); + if(!noclear) + memset((void*)(p->pa|KZERO), 0, BY2PG); + p->o = o; + p->va = va; + + return p; +} + +/* + * Move page to head of list + */ +void +usepage(Page *p, int dolock) +{ + if(dolock) + lock(&palloc); + /* + * Unlink + */ + if(p->prev) + p->prev->next = p->next; + else + palloc.head = p->next; + if(p->next) + p->next->prev = p->prev; + else + palloc.tail = p->prev; + /* + * Link + */ + p->next = palloc.head; + p->prev = 0; + if(p->next) + p->next->prev = p; + else + palloc.tail = p; + palloc.head = p; + if(dolock) + unlock(&palloc); +} + +Orig* +lookorig(ulong va, ulong npte, int flag, Chan *c) +{ + Orig *o; + ulong i; + + for(o=origalloc.arena,i=0; inpage && o->qid==c->qid && o->va==va){ + lock(o); + if(o->npage && o->qid==c->qid) + if(o->va==va && o->npte==npte && o->flag==flag) + if(o->type==c->type && o->dev==c->dev){ + if(o->chan == 0){ + o->chan = c; + incref(c); + } + o->nproc++; + unlock(o); + return o; + } + unlock(o); + } + return 0; +} + +Orig* +neworig(ulong va, ulong npte, int flag, Chan *c) +{ + Orig *o; + int i, freed; + + lock(&origalloc); +loop: + if(o = origalloc.free){ /* assign = */ + origalloc.free = o->next; + o->va = va; + o->pte = 0; + o->flag = flag; + o->nproc = 1; + o->npage = 0; + o->chan = c; + if(c){ + o->type = c->type; + o->dev = c->dev; + o->qid = c->qid; + incref(c); + }else{ + o->type = -1; + o->dev = -1; + o->qid = -1; + } + growpte(o, npte); + unlock(&origalloc); + return o; + } + /* + * This is feeble. Orig's should perhaps be held in + * an LRU list. This algorithm is too aggressive. + */ + freed = 0; + for(o=origalloc.arena,i=0; inproc==0 && canlock(o)){ + if(o->nproc){ + unlock(o); + continue; + } + freepage(o); + freepte(o); + unlock(o); + o->next = origalloc.free; + origalloc.free = o; + freed++; + } + } + if(freed) + goto loop; + print("no origs freed\n"); + unlock(&origalloc); + if(u == 0) + panic("neworig"); + u->p->state = Wakeme; + alarm(1000, wakeme, u->p); + sched(); + lock(&origalloc); + goto loop; +} + +PTE* +newmod(void) +{ + PTEA *pte; + +loop: + lock(&modalloc); + if(pte = modalloc.free){ /* assign = */ + modalloc.free = pte->next; + unlock(&modalloc); + memset(pte, 0, sizeof(PTE)); + return pte; + } + unlock(&modalloc); + print("no mods\n"); + if(u == 0) + panic("newmod"); + u->p->state = Wakeme; + alarm(1000, wakeme, u->p); + sched(); + goto loop; +} + +/* + * Duplicate mod structure for this segment (old) in new process p. + * old->o must be locked. + */ +void +forkmod(Seg *old, Seg *new, Proc *p) +{ + Orig *o; + PTE *pte, *ppte, *opte, *npte; + ulong va; + + o = old->o; + 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(); + npte->proc = p; + npte->page = pte->page; + pte->page->ref++; + o->npage++; + /* + * Link into mod list for this va + */ + npte->nextmod = pte->nextmod; + pte->nextmod = npte; + /* + * Link into mod list for new segment + */ + if(ppte == 0) + new->mod = npte; + else + ppte->nextva = npte; + npte->nextva = 0; + ppte = npte; + pte = pte->nextva; + } +} + +void +freesegs(int save) +{ + int i, j; + Seg *s; + Orig *o; + PTE *pte, *opte; + PTEA *old; + Page *pg; + Chan *c; + + s = u->p->seg; + for(i=0; io; + if(o == 0) + continue; + lock(o); + if(pte = s->mod){ /* assign = */ + while(pte){ + opte = &o->pte[(pte->page->va-o->va)>>PGSHIFT]; + while(opte->nextmod != pte){ + if(opte->page && opte->page->va != pte->page->va) + panic("pte %lux %lux\n", opte->page->va, pte->page->va); + opte = opte->nextmod; + if(opte == 0) + panic("freeseg opte==0"); + } + opte->nextmod = pte->nextmod; + pg = pte->page; + if(pg->ref == 1){ + pte->page = 0; + pg->o = 0; + } + pg->ref--; + o->npage--; + old = (PTEA*)pte; + pte = pte->nextva; + lock(&modalloc); + old->next = modalloc.free; + modalloc.free = old; + unlock(&modalloc); + } + } + o->nproc--; + if(o->nproc == 0){ + if(c = o->chan){ /* assign = */ + o->chan = 0; + close(c); + } + if(!(o->flag&OCACHED) || o->npage==0){ + freepage(o); + freepte(o); + unlock(o); + lock(&origalloc); + o->next = origalloc.free; + origalloc.free = o; + unlock(&origalloc); + }else + unlock(o); + }else{ + /* + * BUG: there is a leak here. if the origin pte is being used only + * by the exiting process, the associated page will linger. the fix + * is to remember either the length of the mod list at each va or + * the number of processes sharing the origin pte, and to promote one + * of the mods to the origin pte when no process is left using the + * origin pte. + */ + unlock(o); + } + } +} + +/* + * Adjust segment to desired size. This implementation is rudimentary. + */ +int +segaddr(Seg *s, ulong min, ulong max) +{ + Orig *o; + + if(max < min) + return 0; + if(min != s->minva) /* can't grow down yet (stacks: fault.c) */ + return 0; + max = (max+(BY2PG-1)) & ~(BY2PG-1); + o = s->o; + if(max == s->maxva) + return 1; + if(max > s->maxva){ + /* + * Grow + */ + /* BUG: check spill onto other segments */ + if(o->va+BY2PG*o->npte < max) + growpte(o, (max-o->va)>>PGSHIFT); + s->maxva = max; + return 1; + } + /* + * Shrink + */ + print("segaddr shrink"); + for(;;); +} + +/* + * o is locked + */ +void +freepage(Orig *o) +{ + PTE *pte; + Page *pg; + int i; + + pte = o->pte; + for(i=0; inpte; i++,pte++) + if(pg = pte->page){ /* assign = */ + if(pg->ref == 1){ + pte->page = 0; + pg->o = 0; + } + pg->ref--; + } + o->npage = 0; +} + +/* + * Compacting allocator + */ + +void +freepte(Orig *o) /* o is locked */ +{ + PTEA *p; + p = (PTEA*)(o->pte - 1); + p->o = 0; +} + +void +growpte(Orig *o, ulong n) +{ + PTEA *p; + ulong nfree; + + lock(&ptealloc); + lock(o); + if(o->pte){ + if(o->npte == n) + panic("growpte pointless"); + p = (PTEA*)(o->pte - 1); + if(o->npte > n){ + nfree = o->npte - n; + p->n -= nfree; + o->npte -= nfree; + p += p->n; + p->o = 0; + p->n = nfree; + }else{ + n++; + if(p+p->n == ptealloc.free){ + compactpte(o, n - p->n); + p = (PTEA*)(o->pte - 1); + ptealloc.free += n - p->n; + }else{ + compactpte(o, n); + p = ptealloc.free; + ptealloc.free += n; + memcpy(p+1, o->pte, o->npte*sizeof(PTE)); + p->o = o; + ((PTEA*)(o->pte-1))->o = 0; + o->pte = p+1; + } + memset(p+1+o->npte, 0, (n-(1+o->npte))*sizeof(PTE)); + p->n = n; + o->npte = n-1; + } + unlock(o); + unlock(&ptealloc); + return; + } + n++; + compactpte(o, n); + p = ptealloc.free; + ptealloc.free += n; + memset(p, 0, n*sizeof(PTE)); + p->n = n; + p->o = o; + o->pte = p+1; + o->npte = n-1; + unlock(o); + unlock(&ptealloc); +} + +void +compactpte(Orig *o, ulong n) +{ + PTEA *p1, *p2; + Orig *p2o; + + if(ptealloc.end-ptealloc.free >= n) + return; + p1 = ptealloc.arena; /* dest */ + p2 = ptealloc.arena; /* source */ + while(p2 < ptealloc.free){ + p2o = p2->o; + if(p2o == 0){ + Free: + p2 += p2->n; + continue; + } + if(p1 != p2){ + if(p2o != o) + lock(p2o); + if(p2->o != p2o){ /* freepte()d very recently */ + if(p2->o) + panic("compactpte p2->o %lux\n", p2->o); + unlock(p2o); + goto Free; + } + memcpy(p1, p2, p2->n*sizeof(PTE)); + p2o->pte = p1+1; + if(p2o != o) + unlock(p2o); + } + p2 += p1->n; + p1 += p1->n; + } + ptealloc.free = p1; + if(ptealloc.end-ptealloc.free >= n) + return; + unlock(o); + unlock(&ptealloc); + panic("compactpte %d %lux %d", n, o->va, o->npte); +} diff --git a/port/pgrp.c b/port/pgrp.c new file mode 100644 index 0000000000000000000000000000000000000000..6da4efc58b0a99b7a891c7b1508130ca4ef81a21 --- /dev/null +++ b/port/pgrp.c @@ -0,0 +1,191 @@ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "errno.h" + +struct{ + Lock; + Pgrp *free; + ulong pgrpid; +}pgrpalloc; + +struct{ + Lock; + Mount *free; + ulong mountid; +}mountalloc; + +void +pgrpinit(void) +{ + int i; + Pgrp *p; + Mount *m; + + pgrpalloc.free = ialloc(conf.npgrp*sizeof(Pgrp), 0); + + p = pgrpalloc.free; + for(i=0; inext = p+1; + p->mtab = ialloc(conf.nmtab*sizeof(Mtab), 0); + p->etab = ialloc(conf.npgenv*sizeof(Envp*), 0); + } + p->next = 0; + + mountalloc.free = ialloc(conf.nmount*sizeof(Mount), 0); + + m = mountalloc.free; + for(i=0; inext = m+1; + m->next = 0; +} + +Pgrp* +newpgrp(void) +{ + Pgrp *p; + +loop: + lock(&pgrpalloc); + if(p = pgrpalloc.free){ /* assign = */ + pgrpalloc.free = p->next; + p->ref = 1; + p->pgrpid = ++pgrpalloc.pgrpid; + p->nmtab = 0; + p->nenv = 0; + unlock(&pgrpalloc); + return p; + } + unlock(&pgrpalloc); + print("no pgrps\n"); + if(u == 0) + panic("newpgrp"); + u->p->state = Wakeme; + alarm(1000, wakeme, u->p); + sched(); + goto loop; +} + +void +closepgrp(Pgrp *p) +{ + int i; + Mtab *m; + Envp *ep; + + if(decref(p) == 0){ + m = p->mtab; + for(i=0; inmtab; i++,m++) + if(m->c){ + close(m->c); + closemount(m->mnt); + } + ep = p->etab; + for(i=0; inenv; i++,ep++) + if(ep->env) + envpgclose(ep->env); + lock(&pgrpalloc); + p->next = pgrpalloc.free; + pgrpalloc.free = p; + unlock(&pgrpalloc); + } +} + +Mount* +newmount(void) +{ + Mount *m; + +loop: + lock(&mountalloc); + if(m = mountalloc.free){ /* assign = */ + mountalloc.free = m->next; + m->ref = 1; + m->mountid = ++mountalloc.mountid; + unlock(&mountalloc); + return m; + } + unlock(&mountalloc); + print("no mounts\n"); + if(u == 0) + panic("newmount"); + u->p->state = Wakeme; + alarm(1000, wakeme, u->p); + sched(); + goto loop; +} + +void +closemount(Mount *m) +{ + lock(m); + if(m->ref == 1){ + close(m->c); + if(m->next) + closemount(m->next); + unlock(m); + lock(&mountalloc); + m->mountid = 0; + m->next = mountalloc.free; + mountalloc.free = m; + unlock(&mountalloc); + return; + } + m->ref--; + unlock(m); +} + +void +pgrpcpy(Pgrp *to, Pgrp *from) +{ + int i; + Mtab *m; + Envp *ep; + Env *e; + + lock(from); + memcpy(to->user, from->user, NAMELEN); + memcpy(to->mtab, from->mtab, from->nmtab*sizeof(Mtab)); + to->nmtab = from->nmtab; + m = to->mtab; + for(i=0; inmtab; i++,m++) + if(m->c){ + incref(m->c); + lock(m->mnt); + m->mnt->ref++; + unlock(m->mnt); + } + + to->nenv = from->nenv; + ep = to->etab; + for(i=0; inenv; i++,ep++){ + ep->chref = 0; + e = ep->env = from->etab[i].env; + if(e){ + lock(e); + if(waserror()){ + unlock(e); + unlock(from); + ep->env = 0; + nexterror(); + } + /* + * If pgrp being forked has an open channel + * on this env, it may write it after the fork + * so make a copy now. + * Don't worry about other pgrps, because they + * will copy if they are about to write. + */ + if(from->etab[i].chref){ + ep->env = copyenv(e, 0); + unlock(ep->env); + }else + e->pgref++; + poperror(); + unlock(e); + } + } + unlock(from); +} diff --git a/port/print.c b/port/print.c new file mode 100644 index 0000000000000000000000000000000000000000..5f59dda8872ef0216f2e41e504ec77541fdfeac9 --- /dev/null +++ b/port/print.c @@ -0,0 +1,287 @@ +#include "u.h" +#include "lib.h" + +#define PTR sizeof(char*) +#define SHORT sizeof(int) +#define INT sizeof(int) +#define LONG sizeof(long) +#define IDIGIT 30 +#define MAXCON 30 + +static int convcount = { 10 }; + +#define PUT(o, c) if((o)->p < (o)->ep) *(o)->p++ = c + +static int noconv(Op*); +static int cconv(Op*); +static int dconv(Op*); +static int hconv(Op*); +static int lconv(Op*); +static int oconv(Op*); +static int sconv(Op*); +static int uconv(Op*); +static int xconv(Op*); +static int percent(Op*); + +static +int (*fmtconv[MAXCON])(Op*) = +{ + noconv, + cconv, dconv, hconv, lconv, + oconv, sconv, uconv, xconv, + percent, +}; +static +char fmtindex[128] = +{ + ['c'] 1, + ['d'] 2, + ['h'] 3, + ['l'] 4, + ['o'] 5, + ['s'] 6, + ['u'] 7, + ['x'] 8, + ['%'] 9, +}; + +int +fmtinstall(char c, int (*f)(Op*)) +{ + + c &= 0177; + if(fmtindex[c] == 0) { + if(convcount >= MAXCON) + return 1; + fmtindex[c] = convcount++; + } + fmtconv[fmtindex[c]] = f; + return 0; +} + +char* +donprint(char *p, char *ep, char *fmt, void *argp) +{ + int sf1, c; + Op o; + + o.p = p; + o.ep = ep; + o.argp = argp; + +loop: + c = *fmt++; + if(c != '%') { + if(c == 0) { + if(o.p < o.ep) + *o.p = 0; + return o.p; + } + PUT(&o, c); + goto loop; + } + o.f1 = 0; + o.f2 = -1; + o.f3 = 0; + c = *fmt++; + sf1 = 0; + if(c == '-') { + sf1 = 1; + c = *fmt++; + } + while(c >= '0' && c <= '9') { + o.f1 = o.f1*10 + c-'0'; + c = *fmt++; + } + if(sf1) + o.f1 = -o.f1; + if(c != '.') + goto l1; + c = *fmt++; + while(c >= '0' && c <= '9') { + if(o.f2 < 0) + o.f2 = 0; + o.f2 = o.f2*10 + c-'0'; + c = *fmt++; + } +l1: + if(c == 0) + fmt--; + c = (*fmtconv[fmtindex[c&0177]])(&o); + if(c < 0) { + o.f3 |= -c; + c = *fmt++; + goto l1; + } + o.argp = (char*)o.argp + c; + goto loop; +} + +int +numbconv(Op *op, int base) +{ + char b[IDIGIT]; + int i, f, n, r; + long v; + short h; + + f = 0; + switch(op->f3 & (FLONG|FSHORT|FUNSIGN)) { + case FLONG: + v = *(long*)op->argp; + r = LONG; + break; + + case FUNSIGN|FLONG: + v = *(unsigned long*)op->argp; + r = LONG; + break; + + case FSHORT: + h = *(int*)op->argp; + v = h; + r = SHORT; + break; + + case FUNSIGN|FSHORT: + h = *(int*)op->argp; + v = (unsigned short)h; + r = SHORT; + break; + + default: + v = *(int*)op->argp; + r = INT; + break; + + case FUNSIGN: + v = *(unsigned*)op->argp; + r = INT; + break; + } + if(!(op->f3 & FUNSIGN) && v < 0) { + v = -v; + f = 1; + } + b[IDIGIT-1] = 0; + for(i = IDIGIT-2;; i--) { + n = (unsigned long)v % base; + n += '0'; + if(n > '9') + n += 'a' - ('9'+1); + b[i] = n; + if(i < 2) + break; + v = (unsigned long)v / base; + if(op->f2 >= 0 && i >= IDIGIT-op->f2) + continue; + if(v <= 0) + break; + } +sout: + if(f) + b[--i] = '-'; + strconv(b+i, op, op->f1, -1); + return r; +} + +void +strconv(char *o, Op *op, int f1, int f2) +{ + int n, c; + char *p; + + n = strlen(o); + if(f1 >= 0) + while(n < f1) { + PUT(op, ' '); + n++; + } + for(p=o; c = *p++;) + if(f2 != 0) { + PUT(op, c); + f2--; + } + if(f1 < 0) { + f1 = -f1; + while(n < f1) { + PUT(op, ' '); + n++; + } + } +} + +static int +noconv(Op *op) +{ + + strconv("***", op, 0, -1); + return 0; +} + +static int +cconv(Op *op) +{ + char b[2]; + + b[0] = *(int*)op->argp; + b[1] = 0; + strconv(b, op, op->f1, -1); + return INT; +} + +static int +dconv(Op *op) +{ + + return numbconv(op, 10); +} + +static int +hconv(Op *op) +{ + return -FSHORT; +} + +static int +lconv(Op *op) +{ + + return -FLONG; +} + +static int +oconv(Op *op) +{ + + return numbconv(op, 8); +} + +static int +sconv(Op *op) +{ + + strconv(*(char**)op->argp, op, op->f1, op->f2); + return PTR; +} + +static int +uconv(Op *op) +{ + return -FUNSIGN; +} + +static int +xconv(Op *op) +{ + + return numbconv(op, 16); +} + +static int +percent(Op *op) +{ + + PUT(op, '%'); + return 0; +} diff --git a/port/proc.c b/port/proc.c new file mode 100644 index 0000000000000000000000000000000000000000..e0d156021d781a2112931cff66e3b383c76f9db0 --- /dev/null +++ b/port/proc.c @@ -0,0 +1,541 @@ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "errno.h" + +struct +{ + Lock; + ulong pid; +}pidalloc; + +struct +{ + Lock; + Proc *arena; + Proc *free; +}procalloc; + +struct +{ + Lock; + Proc *head; + Proc *tail; +}runq; + +char *statename[]={ /* BUG: generate automatically */ + "Dead", + "Moribund", + "Zombie", + "Ready", + "Scheding", + "Running", + "Queueing", + "MMUing", + "Exiting", + "Inwait", + "Wakeme", + "Broken", +}; + +/* + * Always splhi()'ed. + */ +void +schedinit(void) /* never returns */ +{ + Proc *p; + + setlabel(&m->sched); + if(u){ + m->proc = 0; + p = u->p; + puttlbx(0, KZERO | PTEPID(0), 0); /* safety first */ + u = 0; + if(p->state == Running) + ready(p); + else if(p->state == Moribund){ + p->pid = 0; + unlock(&p->debug); + p->upage->ref--; + /* procalloc already locked */ + p->qnext = procalloc.free; + procalloc.free = p; + p->upage = 0; + unlock(&procalloc); + p->state = Dead; + } + p->mach = 0; + } + sched(); +} + +void +sched(void) +{ + Proc *p; + ulong tlbvirt, tlbphys; + void (*f)(ulong); + + if(u){ + splhi(); + if(setlabel(&u->p->sched)){ /* woke up */ + p = u->p; + p->state = Running; + p->mach = m; + m->proc = p; + spllo(); + return; + } + gotolabel(&m->sched); + } + if(f = m->intr){ /* assign = */ + m->intr = 0; + (*f)(m->cause); + } + spllo(); + p = runproc(); + splhi(); + mapstack(p); + gotolabel(&p->sched); +} + +void +ready(Proc *p) +{ + int s; + + s = splhi(); + lock(&runq); + p->rnext = 0; + if(runq.tail) + runq.tail->rnext = p; + else + runq.head = p; + runq.tail = p; + p->state = Ready; + unlock(&runq); + splx(s); +} + +/* + * Always called spllo + */ +Proc* +runproc(void) +{ + Proc *p; + int i; + +loop: + while(runq.head == 0) + for(i=0; i<10; i++) + ; + splhi(); + lock(&runq); + p = runq.head; + if(p==0 || p->mach){ /* p->mach==0 only when process state is saved */ + unlock(&runq); + spllo(); + goto loop; + } + if(p->rnext == 0) + runq.tail = 0; + runq.head = p->rnext; + if(p->state != Ready) + print("runproc %s %d %s\n", p->text, p->pid, statename[p->state]); + unlock(&runq); + p->state = Scheding; + spllo(); + return p; +} + +Proc* +newproc(void) +{ + Proc *p; + +loop: + lock(&procalloc); + if(p = procalloc.free){ /* assign = */ + procalloc.free = p->qnext; + p->state = Zombie; + unlock(&procalloc); + p->mach = 0; + p->qnext = 0; + p->nchild = 0; + p->child = 0; + p->exiting = 0; + memset(p->pidonmach, 0, sizeof p->pidonmach); + memset(p->seg, 0, sizeof p->seg); + lock(&pidalloc); + p->pid = ++pidalloc.pid; + unlock(&pidalloc); + if(p->pid == 0) + panic("pidalloc"); + return p; + } + unlock(&procalloc); + print("no procs\n"); + if(u == 0) + panic("newproc"); + alarm(1000, wakeme, u->p); + sched(); + goto loop; +} + +void +procinit0(void) /* bad planning - clashes with devproc.c */ +{ + Proc *p; + int i; + + print("procinit\n"); + + procalloc.free = ialloc(conf.nproc*sizeof(Proc), 0); + procalloc.arena = procalloc.free; + + p = procalloc.free; + for(i=0; iqnext = p+1; + p->qnext = 0; +} + +void +sleep1(Rendez *r, int (*f)(void*), void *arg) +{ + Proc *p; + int s; + + /* + * spl is to allow lock to be called + * at interrupt time. lock is mutual exclusion + */ + s = splhi(); + lock(r); + + /* + * if condition happened, never mind + */ + if((*f)(arg)){ + unlock(r); + splx(s); + return; + } + + /* + * now we are committed to + * change state and call scheduler + */ + p = u->p; + if(r->p) + print("double sleep %d\n", r->p->pid); + p->r = r; + p->wokeup = 0; + p->state = Wakeme; + r->p = p; + unlock(r); +} + +void +sleep(Rendez *r, int (*f)(void*), void *arg) +{ + sleep1(r, f, arg); + sched(); + if(u->p->wokeup){ + u->p->wokeup = 0; + error(0, Eintr); + } +} + +void +tsleep(Rendez *r, int (*f)(void*), void *arg, int ms) +{ + Alarm *a; + + sleep1(r, f, arg); + a = alarm(ms, twakeme, r); + sched(); + cancel(a); + if(u->p->wokeup){ + u->p->wokeup = 0; + error(0, Eintr); + } +} + +void +wakeup(Rendez *r) +{ + Proc *p; + int s; + + s = splhi(); + lock(r); + p = r->p; + if(p){ + r->p = 0; + if(p->state != Wakeme) + panic("wakeup: not Wakeme"); + p->r = 0; + ready(p); + } + unlock(r); + splx(s); +} + +int +postnote(Proc *p, int dolock, char *n, int flag) +{ + User *up; + int s; + Rendez *r; + + if(dolock) + lock(&p->debug); + up = (User*)(p->upage->pa|KZERO); + if(flag!=NUser && (up->notify==0 || up->notified)) + up->nnote = 0; /* force user's hand */ + else if(up->nnote == NNOTE-1) + return 0; + strcpy(up->note[up->nnote].msg, n); + up->note[up->nnote++].flag = flag; + if(dolock) + unlock(&p->debug); + if(r = p->r){ /* assign = */ + /* wake up */ + s = splhi(); + lock(r); + if(p->r==r && r->p==p){ + r->p = 0; + if(p->state != Wakeme) + panic("postnote wakeup: not Wakeme"); + p->wokeup = 1; + p->r = 0; + ready(p); + } + unlock(r); + splx(s); + } + return 1; +} + +void +wakeme(Alarm *a) +{ + ready((Proc*)(a->arg)); + cancel(a); +} + +void +twakeme(Alarm *a) +{ + wakeup((Rendez*)(a->arg)); +} + +void +pexit(char *s, int freemem) +{ + char status[64]; + ulong mypid; + Proc *p; + Waitmsg w; + int n; + Chan *c; + ulong *up, *ucp, *wp; + + mypid = u->p->pid; + if(s) + strcpy(status, s); + else + status[0] = 0; + if(freemem){ + freesegs(-1); + closepgrp(u->p->pgrp); + close(u->dot); + } + for(n=0; n<=u->maxfd; n++) + if(c = u->fd[n]) /* assign = */ + close(c); + /* + * Any of my children exiting? + */ + while(u->p->nchild){ + lock(&u->p->wait.queue); + if(canlock(&u->p->wait.use)){ /* no child is exiting */ + u->p->exiting = 1; + unlock(&u->p->wait.use); + unlock(&u->p->wait.queue); + break; + }else{ /* must wait for child */ + unlock(&u->p->wait.queue); + pwait(0); + } + } + + u->p->time[TReal] = MACHP(0)->ticks - u->p->time[TReal]; + /* + * Tell my parent + */ + p = u->p->parent; + if(p == 0) + goto out; + qlock(&p->wait); + lock(&p->wait.queue); + if(p->pid==u->p->parentpid && !p->exiting){ + w.pid = mypid; + strcpy(w.msg, status); + wp = &w.time[TUser]; + up = &u->p->time[TUser]; + ucp = &u->p->time[TCUser]; + *wp++ = (*up++ + *ucp++)*MS2HZ; + *wp++ = (*up++ + *ucp )*MS2HZ; + *wp = (*up )*MS2HZ; + p->child = u->p; + /* + * Pass info through back door, to avoid huge Proc's + */ + p->waitmsg = (Waitmsg*)(u->p->upage->pa|(((ulong)&w)&(BY2PG-1))|KZERO); + u->p->state = Exiting; + if(p->state == Inwait) + ready(p); + unlock(&p->wait.queue); + sched(); + }else{ + unlock(&p->wait.queue); + qunlock(&p->wait); + } + out: + if(!freemem){ + u->p->state = Broken; + sched(); /* until someone lets us go */ + freesegs(-1); + closepgrp(u->p->pgrp); + close(u->dot); + } + lock(&procalloc); /* sched() can't do this */ + lock(&u->p->debug); /* sched() can't do this */ + u->p->state = Moribund; + sched(); /* never returns */ +} + +ulong +pwait(Waitmsg *w) +{ + Proc *c, *p; + ulong cpid; + + p = u->p; +again: + while(canlock(&p->wait.use)){ + if(p->nchild == 0){ + qunlock(&p->wait); + error(0, Enochild); + } + p->state = Inwait; + qunlock(&p->wait); + sched(); + } + lock(&p->wait.queue); /* wait until child is finished */ + c = p->child; + if(c == 0){ + print("pwait %d\n", p->pid); + p->state = Inwait; + unlock(&p->wait.queue); + sched(); + goto again; + } + p->child = 0; + if(w) + *w = *p->waitmsg; + cpid = p->waitmsg->pid; + p->time[TCUser] += c->time[TUser] + c->time[TCUser]; + p->time[TCSys] += c->time[TSys] + c->time[TCSys]; + p->time[TCReal] += c->time[TReal]; + p->nchild--; + unlock(&p->wait.queue); + qunlock(&p->wait); + ready(c); + return cpid; +} + + +Proc* +proctab(int i) +{ + return &procalloc.arena[i]; +} + +#include +DEBUG() +{ + int i; + Proc *p; + + print("DEBUG\n"); + for(i=0; istate != Dead) + print("%d:%s upc %lux %s ut %ld st %ld\n", + p->pid, p->text, p->pc, statename[p->state], + p->time[0], p->time[1]); + } +} + +void +kproc(char *name, void (*func)(void *), void *arg) +{ + Proc *p; + int n; + ulong upa; + int lastvar; /* used to compute stack address */ + User *up; + + /* + * Kernel stack + */ + p = newproc(); + p->upage = newpage(1, 0, USERADDR|(p->pid&0xFFFF)); + upa = p->upage->pa|KZERO; + up = (User *)upa; + + /* + * Save time: only copy u-> data and useful stack + */ + memcpy((void*)upa, u, sizeof(User)); + n = USERADDR+BY2PG - (ulong)&lastvar; + n = (n+32) & ~(BY2WD-1); /* be safe & word align */ + memcpy((void*)(upa+BY2PG-n), (void*)((u->p->upage->pa|KZERO)+BY2PG-n), n); + ((User *)upa)->p = p; + + /* + * Refs + */ + incref(up->dot); + for(n=0; n<=up->maxfd; n++) + up->fd[n] = 0; + up->maxfd = 0; + + /* + * Sched + */ + if(setlabel(&p->sched)){ + u->p = p; + p->state = Running; + p->mach = m; + m->proc = p; + spllo(); + strncpy(p->text, name, sizeof p->text); + (*func)(arg); + pexit(0, 1); + } + p->pgrp = u->p->pgrp; + incref(p->pgrp); + p->nchild = 0; + p->parent = 0; + memset(p->time, 0, sizeof(p->time)); + p->time[TReal] = MACHP(0)->ticks; + ready(p); + flushmmu(); +} diff --git a/port/stream.c b/port/stream.c new file mode 100644 index 0000000000000000000000000000000000000000..2494f3914366efe2d58b2e7d73b2a9e35e2da170 --- /dev/null +++ b/port/stream.c @@ -0,0 +1,886 @@ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" +#include "errno.h" +#include "devtab.h" + +static void stputq(Queue*, Block*); +Qinfo procinfo = { stputq, nullput, 0, 0, "process" } ; +extern Qinfo noetherinfo; + +static Qinfo *lds[] = { + &noetherinfo, + 0 +}; + +enum { + Nclass=4, +}; + +/* + * All stream structures are ialloc'd at boot time + */ +Stream *slist; +Queue *qlist; +Block *blist; +static Lock garbagelock; + +/* + * The block classes. There are Nclass block sizes, each with its own free list. + * All are ialloced at qinit() time. + */ +typedef struct { + int size; + Queue; +} Bclass; +Bclass bclass[Nclass]={ + { 0 }, + { 64 }, + { 512 }, + { 4096 }, +}; + +/* + * Allocate streams, queues, and blocks. Allocate n block classes with + * 1/2(m+1) to class m < n-1 + * 1/2(n-1) to class n-1 + */ +void +streaminit(void) +{ + int class, i, n; + Block *bp; + Bclass *bcp; + + slist = (Stream *)ialloc(conf.nstream * sizeof(Stream), 0); + qlist = (Queue *)ialloc(conf.nqueue * sizeof(Queue), 0); + blist = (Block *)ialloc(conf.nblock * sizeof(Block), 0); + bp = blist; + n = conf.nblock; + for(class = 0; class < Nclass; class++){ + if(class < Nclass-1) + n = n/2; + bcp = &bclass[class]; + for(i = 0; i < n; i++) { + if(bcp->size) + bp->base = (uchar *)ialloc(bcp->size, 0); + bp->lim = bp->base + bcp->size; + bp->flags = class; + freeb(bp); + bp++; + } + } +} + + +/* + * allocate a block + */ +static int +isblock(void *arg) +{ + Bclass *bcp; + + bcp = (Bclass *)arg; + return bcp->first!=0; +} +Block * +allocb(ulong size) +{ + Block *bp; + Bclass *bcp; + int i; + + + /* + * map size to class + */ + for(bcp=bclass; bcp->sizefirst == 0){ + unlock(bcp); + print("waiting for blocks\n"); + sleep(&bcp->r, isblock, (void *)bcp); + lock(bcp); + } + bp = bcp->first; + bcp->first = bp->next; + if(bcp->first == 0) + bcp->last = 0; + unlock(bcp); + + /* + * return an empty block + */ + bp->rptr = bp->wptr = bp->base; + bp->next = 0; + bp->type = M_DATA; + bp->flags &= S_CLASS; + return bp; +} + +/* + * Free a block. Poison its pointers so that someone trying to access + * it after freeing will cause a dump. + */ +void +freeb(Block *bp) +{ + Bclass *bcp; + + bcp = &bclass[bp->flags & S_CLASS]; + bp->rptr = bp->wptr = 0; + lock(bcp); + if(bcp->first) + bcp->last->next = bp; + else + bcp->first = bp; + bcp->last = bp; + bp->next = 0; + wakeup(&bcp->r); + unlock(bcp); +} + +/* + * allocate a pair of queues. flavor them with the requested put routines. + * the `QINUSE' flag on the read side is the only one used. + */ +static Queue * +allocq(Qinfo *qi) +{ + Queue *q, *wq; + + for(q=qlist; q<&qlist[conf.nqueue]; q++, q++) { + if(q->flag == 0){ + if(canlock(q)){ + if(q->flag == 0) + break; + unlock(q); + } + } + } + + if(q == &qlist[conf.nqueue]){ + print("no more queues\n"); + error(0, Enoqueue); + } + + q->flag = QINUSE; + q->r.p = 0; + q->info = qi; + q->put = qi->iput; + wq = q->other = q + 1; + + wq->r.p = 0; + wq->info = qi; + wq->put = qi->oput; + wq->other = q; + + unlock(q); + + return q; +} + +/* + * free a queue + */ +static void +freeq(Queue *q) +{ + Block *bp; + + q = RD(q); + while(bp = getq(q)) + freeb(bp); + q = WR(q); + while(bp = getq(q)) + freeb(bp); + RD(q)->flag = 0; +} + +/* + * push a queue onto a stream referenced by the proc side write q + */ +Queue * +pushq(Stream* s, Qinfo *qi) +{ + Queue *q; + Queue *nq; + + q = RD(s->procq); + + /* + * make the new queue + */ + nq = allocq(qi); + + /* + * push + */ + RD(nq)->next = q; + RD(WR(q)->next)->next = RD(nq); + WR(nq)->next = WR(q)->next; + WR(q)->next = WR(nq); + + if(qi->open) + (*qi->open)(RD(nq), s); + + return WR(nq)->next; +} + +/* + * pop off the top line discipline + */ +static void +popq(Stream *s) +{ + Queue *q; + + if(s->procq->next == WR(s->devq)) + error(0, Ebadld); + q = s->procq->next; + if(q->info->close) + (*q->info->close)(RD(q)); + s->procq->next = q->next; + RD(q->next)->next = RD(s->procq); + freeq(q); +} + +/* + * add a block (or list of blocks) to the end of a queue. return true + * if one of the blocks contained a delimiter. + */ +int +putq(Queue *q, Block *bp) +{ + int delim; + + delim = 0; + lock(q); + if(q->first) + q->last->next = bp; + else + q->first = bp; + q->len += bp->wptr - bp->rptr; + delim = bp->flags & S_DELIM; + while(bp->next) { + bp = bp->next; + q->len += bp->wptr - bp->rptr; + delim |= bp->flags & S_DELIM; + } + q->last = bp; + if(q->len >= Streamhi) + q->flag |= QHIWAT; + unlock(q); + return delim; +} +int +putb(Blist *q, Block *bp) +{ + int delim; + + delim = 0; + if(q->first) + q->last->next = bp; + else + q->first = bp; + q->len += bp->wptr - bp->rptr; + delim = bp->flags & S_DELIM; + while(bp->next) { + bp = bp->next; + q->len += bp->wptr - bp->rptr; + delim |= bp->flags & S_DELIM; + } + q->last = bp; + bp->next = 0; + return delim; +} + +/* + * add a block to the start of a queue + */ +static void +putbq(Blist *q, Block *bp) +{ + lock(q); + if(q->first) + bp->next = q->first; + else + q->last = bp; + q->first = bp; + q->len += bp->wptr - bp->rptr; + unlock(q); +} + +/* + * remove the first block from a queue + */ +Block * +getq(Queue *q) +{ + Block *bp; + + lock(q); + bp = q->first; + if(bp) { + q->first = bp->next; + if(q->first == 0) + q->last = 0; + q->len -= bp->wptr - bp->rptr; + if((q->flag&QHIWAT) && q->len < Streamhi/2){ + wakeup(&q->other->next->other->r); + q->flag &= ~QHIWAT; + } + bp->next = 0; + } + unlock(q); + return bp; +} +Block * +getb(Blist *q) +{ + Block *bp; + + bp = q->first; + if(bp) { + q->first = bp->next; + if(q->first == 0) + q->last = 0; + q->len -= bp->wptr - bp->rptr; + bp->next = 0; + } + return bp; +} + +/* + * put a block into the bit bucket + */ +void +nullput(Queue *q, Block *bp) +{ + freeb(bp); + error(0, Ehungup); +} + +/* + * find the info structure for line discipline 'name' + */ +static Qinfo * +qinfofind(char *name) +{ + Qinfo **qip; + + if(name == 0) + error(0, Ebadld); + for(qip = lds; *qip; qip++) + if(strcmp((*qip)->name, name)==0) + return *qip; + error(0, Ebadld); +} + +/* + * send a hangup up a stream + */ +static void +hangup(Stream *s) +{ + Block *bp; + + bp = allocb(0); + bp->type = M_HANGUP; + (*s->devq->put)(s->devq, bp); +} + +/* + * parse a string and return a pointer to the second element if the + * first matches name. bp->rptr will be updated to point to the + * second element. + * + * return 0 if no match. + * + * it is assumed that the block data is null terminated. streamwrite + * guarantees this. + */ +int +streamparse(char *name, Block *bp) +{ + int len; + + len = strlen(name); + if(bp->wptr - bp->rptr < len) + return 0; + if(strncmp(name, (char *)bp->rptr, len)==0){ + if(bp->rptr[len] == ' ') + bp->rptr += len+1; + else if(bp->rptr[len]) + return 0; + else + bp->rptr += len; + return 1; + } + return 0; +} + +/* + * the per stream directory structure + */ +Dirtab streamdir[]={ + "data", Sdataqid, 0, 0600, + "ctl", Sctlqid, 0, 0600, +}; + +/* + * A stream device consists of the contents of streamdir plus + * any directory supplied by the actual device. + * + * values of s: + * 0 to ntab-1 apply to the auxiliary directory. + * ntab to ntab+Shighqid-Slowqid+1 apply to streamdir. + */ +int +streamgen(Chan *c, Dirtab *tab, int ntab, int s, Dir *dp) +{ + Proc *p; + char buf[NAMELEN]; + + if(s < ntab) + tab = &tab[s]; + else if(s < ntab + Shighqid - Slowqid + 1) + tab = &streamdir[s - ntab]; + else + return -1; + + devdir(c, STREAMQID(STREAMID(c->qid),tab->qid), tab->name, tab->length, + tab->perm, dp); + return 1; +} + +/* + * create a new stream + */ +Stream * +streamnew(Chan *c, Qinfo *qi) +{ + Stream *s; + Queue *q; + + /* + * find a free stream struct + */ + for(s = slist; s < &slist[conf.nstream]; s++) { + if(s->inuse == 0){ + if(canlock(s)){ + if(s->inuse == 0) + break; + unlock(s); + } + } + } + if(s == &slist[conf.nstream]){ + print("no more streams\n"); + error(0, Enostream); + } + if(waserror()){ + unlock(s); + streamclose(c); + nexterror(); + } + + /* + * marry a stream and a channel + */ + if(c){ + c->stream = s; + s->type = c->type; + s->dev = c->dev; + s->id = STREAMID(c->qid); + } else + s->type = -1; + + /* + * hang a device and process q off the stream + */ + s->inuse = 1; + s->tag[0] = 0; + q = allocq(&procinfo); + s->procq = WR(q); + q = allocq(qi); + s->devq = RD(q); + WR(s->procq)->next = WR(s->devq); + RD(s->procq)->next = 0; + RD(s->devq)->next = RD(s->procq); + WR(s->devq)->next = 0; + + if(qi->open) + (*qi->open)(RD(s->devq), s); + + c->flag |= COPEN; + unlock(s); + poperror(); + return s; +} + +/* + * (Re)open a stream. If this is the first open, create a stream. + */ +void +streamopen(Chan *c, Qinfo *qi) +{ + Stream *s; + Queue *q; + + /* + * if the stream already exists, just up the reference count. + */ + for(s = slist; s < &slist[conf.nstream]; s++) { + if(s->inuse && s->type == c->type && s->dev == c->dev + && s->id == STREAMID(c->qid)){ + lock(s); + if(s->inuse && s->type == c->type + && s->dev == c->dev + && s->id == STREAMID(c->qid)){ + s->inuse++; + c->stream = s; + unlock(s); + return; + } + unlock(s); + } + } + + /* + * create a new stream + */ + streamnew(c, qi); +} + +/* + * On the last close of a stream, for each queue on the + * stream release its blocks and call its close routine. + */ +void +streamclose(Chan *c) +{ + Queue *q, *nq; + Block *bp; + + /* + * if not open, ignore it + */ + if(!(c->flag & COPEN)) + return; + + /* + * decrement the reference cound + */ + lock(c->stream); + if(--(c->stream->inuse) != 0){ + unlock(c->stream); + return; + } + + /* + * descend the stream closing the queues + */ + for(q = c->stream->procq; q; q = q->next){ + if(q->info->close) + (*q->info->close)(q->other); + if(q == c->stream->devq->other) + break; + } + /* + * ascend the stream freeing the queues + */ + for(q = c->stream->devq; q; q = nq){ + nq = q->next; + freeq(q); + } + c->stream->id = c->stream->dev = c->stream->type = 0; + unlock(c->stream); +} + +/* + * put a block to be read into the queue. wakeup any waiting reader + */ +void +stputq(Queue *q, Block *bp) +{ + int i; + + if(bp->type == M_HANGUP){ + freeb(bp); + q->flag |= QHUNGUP; + q->other->flag |= QHUNGUP; + } else { + lock(q); + if(q->first) + q->last->next = bp; + else + q->first = bp; + q->last = bp; + q->len += bp->wptr - bp->rptr; + if(q->len >= Streamhi) + q->flag |= QHIWAT; + unlock(q); + } + wakeup(&q->r); +} + +/* + * read a string. update the offset accordingly. + */ +long +stringread(Chan *c, uchar *buf, long n, char *str) +{ + long i; + + i = strlen(str); + i -= c->offset; + if(ioffset, str, n); + c->offset += n; + return n; +} + +/* + * return true if there is an output buffer available + */ +static int +isinput(void *x) +{ + return ((Queue *)x)->first != 0; +} + +/* + * read until we fill the buffer or until a DELIM is encountered + */ +long +streamread(Chan *c, void *vbuf, long n) +{ + Block *bp; + Stream *s; + Queue *q; + long rv = 0; + int left, i, x; + uchar *buf = vbuf; + char num[32]; + + s = c->stream; + switch(STREAMTYPE(c->qid)){ + case Sdataqid: + break; + case Sctlqid: + sprint(num, "%d", s->id); + return stringread(c, buf, n, num); + default: + if(CHDIR & c->qid) + return devdirread(c, vbuf, n, 0, 0, streamgen); + else + panic("streamread"); + } + + /* + * one reader at a time + */ + qlock(&s->rdlock); + if(waserror()){ + qunlock(&s->rdlock); + nexterror(); + } + + /* + * sleep till data is available + */ + q = RD(s->procq); + left = n; + while(left){ + bp = getq(q); + if(bp == 0){ + if(q->flag & QHUNGUP) + break; + sleep(&q->r, &isinput, (void *)q); + continue; + } + + i = bp->wptr - bp->rptr; + if(i <= left){ + memcpy(buf, bp->rptr, i); + left -= i; + buf += i; + if(bp->flags & S_DELIM){ + freeb(bp); + break; + } else + freeb(bp); + } else { + memcpy(buf, bp->rptr, left); + bp->rptr += left; + putbq(q, bp); + left = 0; + } + }; + + qunlock(&s->rdlock); + poperror(); + return n - left; +} + +/* + * Handle a ctl request. Streamwide requests are: + * + * hangup -- send an M_HANGUP up the stream + * push ldname -- push the line discipline named ldname + * pop -- pop a line discipline + * + * This routing is entrered with s->wrlock'ed and must unlock. + */ +static long +streamctlwrite(Stream *s, void *a, long n) +{ + Qinfo *qi; + Block *bp; + + /* + * package + */ + bp = allocb(n+1); + memcpy(bp->wptr, a, n); + bp->wptr[n] = 0; + bp->wptr += n + 1; + + /* + * check for standard requests + */ + if(streamparse("hangup", bp)){ + hangup(s); + freeb(bp); + } else if(streamparse("push", bp)){ + qi = qinfofind((char *)bp->rptr); + pushq(s, qi); + freeb(bp); + } else if(streamparse("pop", bp)){ + popq(s); + freeb(bp); + } else { + bp->type = M_CTL; + bp->flags |= S_DELIM; + PUTNEXT(s->procq, bp); + } + + return n; +} + +/* + * wait till there's room in the next stream + */ +static int +notfull(void *arg) +{ + Queue *q; + + q = (Queue *)arg; + return q->len < Streamhi; +} +void +flowctl(Queue *q) +{ + if(q->next->len >= Streamhi) + sleep(&q->r, notfull, q->next); +} + +/* + * send the request as a single delimited block + */ +long +streamwrite(Chan *c, void *a, long n) +{ + Stream *s; + Block *bp; + Queue *q; + long rem; + int i; + + /* + * one writer at a time + */ + s = c->stream; + qlock(&s->wrlock); + if(waserror()){ + qunlock(&s->wrlock); + nexterror(); + } + + /* + * decode the qid + */ + switch(STREAMTYPE(c->qid)){ + case Sdataqid: + break; + case Sctlqid: + n = streamctlwrite(s, a, n); + qunlock(&s->wrlock); + poperror(); + return n; + default: + panic("bad stream qid\n"); + } + + /* + * No writes allowed on hungup channels + */ + q = s->procq; + if(q->other->flag & QHUNGUP) + error(0, Ehungup); + + if(GLOBAL(a) || n==0){ + /* + * `a' is global to the whole system, just create a + * pointer to it and pass it on. + */ + flowctl(q); + bp = allocb(0); + bp->rptr = bp->base = (uchar *)a; + bp->wptr = bp->lim = (uchar *)a+n; + bp->flags |= S_DELIM; + bp->type = M_DATA; + PUTNEXT(q, bp); + } else { + /* + * `a' is in the user's address space, copy it into + * system buffers and pass the buffers on. + */ + for(rem = n; ; rem -= i) { + flowctl(q); + bp = allocb(rem); + i = bp->lim - bp->wptr; + if(i >= rem){ + memcpy(bp->wptr, a, rem); + bp->flags |= S_DELIM; + bp->wptr += rem; + bp->type = M_DATA; + PUTNEXT(q, bp); + break; + } else { + memcpy(bp->wptr, a, i); + bp->wptr += i; + bp->type = M_DATA; + PUTNEXT(q, bp); + a = ((char*)a) + i; + } + } + } + qunlock(&s->wrlock); + poperror(); + return n; +} diff --git a/port/sturp.c b/port/sturp.c new file mode 100644 index 0000000000000000000000000000000000000000..e1675055577c326cd4c1df32333b5b2f85f55856 --- /dev/null +++ b/port/sturp.c @@ -0,0 +1,808 @@ +#include "syslibc.h" +#include "lock.h" +#include "chan.h" +#include "proc.h" +#include "user.h" +#include "errno.h" +#include "lint.h" +#include "mem.h" +#include "mempool.h" +#include "stream.h" +#include "dkparam.h" +#include "misc.h" + +enum { + Nurp= 32, + MSrexmit= 1000, +}; + +typedef struct Urp Urp; + +/* + * URP status + */ +struct urpstat { + ulong input; /* bytes read from urp */ + ulong output; /* bytes output to urp */ + ulong rxmit; /* retransmit rejected urp msg */ + ulong rjtrs; /* reject, trailer size */ + ulong rjpks; /* reject, packet size */ + ulong rjseq; /* reject, sequence number */ + ulong levelb; /* unknown level b */ + ulong enqsx; /* enqs sent */ + ulong enqsr; /* enqs rcved */ +} urpstat; + +struct Urp { + Qlock; + short state; /* flags */ + + /* input */ + + ulong iwindow; /* input window */ + uchar iseq; /* last good input sequence number */ + uchar lastecho; /* last echo/rej sent */ + uchar trbuf[3]; /* trailer being collected */ + short trx; /* # bytes in trailer being collected */ + + /* output */ + + Queue *rq; + Queue *wq; + int XW; /* blocks per xmit window */ + int maxblock; /* max block size */ + int timeout; /* a timeout has occurred */ + int WS; /* start of current window */ + int WACK; /* first non-acknowledged message */ + int WNX; /* next message to be sent */ + Rendez r; /* process waiting in urpoput */ + Rendez kr; /* process waiting in urpoput */ + Block *xb[8]; /* the xmit window buffer */ + uchar timer; /* timeout for xmit */ +}; +#define WINDOW(u) ((u->WS + u->XW - u->WNX)%8) +#define BETWEEN(x, s, n) (s<=n ? x>=s && x=s) +#define UNACKED(x, u) (BETWEEN(x, u->WACK, u->WNX) + +/* + * Protocol control bytes + */ +#define SEQ 0010 /* sequence number, ends trailers */ +#undef ECHO +#define ECHO 0020 /* echos, data given to next queue */ +#define REJ 0030 /* rejections, transmission error */ +#define ACK 0040 /* acknowledgments */ +#define BOT 0050 /* beginning of trailer */ +#define BOTM 0051 /* beginning of trailer, more data follows */ +#define BOTS 0052 /* seq update algorithm on this trailer */ +#define SOU 0053 /* start of unsequenced trailer */ +#define EOU 0054 /* end of unsequenced trailer */ +#define ENQ 0055 /* xmitter requests flow/error status */ +#define CHECK 0056 /* xmitter requests error status */ +#define INITREQ 0057 /* request initialization */ +#define INIT0 0060 /* disable trailer processing */ +#define INIT1 0061 /* enable trailer procesing */ +#define AINIT 0062 /* response to INIT0/INIT1 */ +#undef DELAY +#define DELAY 0100 /* real-time printing delay */ +#define BREAK 0110 /* Send/receive break (new style) */ + +#define REXMITING 0001 +#define REXMIT 0002 +#define INITING 0004 + +Urp urp[Nurp]; + +/* + * predeclared + */ +static void urpiput(Queue*, Block*, Rendez*); +static void urpoput(Queue*, Block*, Rendez*); +static void urpopen(Queue*, Stream*); +static void urpclose(Queue *); +static void rcvack(Urp*, int); +static void flushinput(Urp*); +static void sendctl(Queue*, int); +static void queuectl(Urp*, int); +static void initoutput(Urp*, int); +static void initinput(Urp*, int); + +Qinfo urpinfo = { urpiput, urpoput, urpopen, urpclose, "urp" }; + +int +urpopen(Queue *q, Stream *s) +{ + Urp *up; + int i; + + /* + * find a free urp structure + */ + for(up = urp; up < &urp[Nurp]; up++){ + qlock(up); + if(up->state == 0) + break; + qunlock(up); + } + if(up == &urp[Nurp]) + error(0, Egreg); + + q->ptr = = q->other->ptr = up; + up->rq = q; + up->wq = WR(q); + q->put = urpciput; + qunlock(up); + initinput(up, 0); + initoutput(up, 0); +} + +/* + * Shut it down. + */ +static int +allacked(void *a) +{ + Urp *up; + + up = (Urp *)a; + return up->WACK == up->WNX; +} +urpclose(Queue *q) +{ + Block *bp; + Urp *up; + int i; + + up = (Urp *)q->ptr; + up->state |= LCLOSE; + + /* + * wait for output to get acked + */ + while(!urpdone(up)) + sleep(&up->r, urpdone, up); + up->state = 0; +} + +/* + * upstream control messages + */ +static void +urpctliput(Urp *up, Queue *q, Block *bp) +{ + switch(bp->type){ + case M_HANGUP: + /* + * ack all outstanding messages + */ + lock(up); + up->state &= ~(INITING); + up->state |= RCLOSE; + unlock(up); + if(up->WSWNX) + urprack(up, ECHO+((up->WNX-1)&07)); + } + PUTNEXT(q, bp); +} + +/* + * character mode input. the last character in EVERY block is + * a control character. + */ +void +urpciput(Queue *q, Block *bp, Rendez *rp) +{ + Urp *up; + int i, full; + Block *nbp; + + up = (Urp *)q->ptr; + if(bp->type != M_DATA){ + urpctliput(up, q, bp); + return; + } + + /* + * get the control character + */ + if(bp->wptr > bp->rptr) + ctl = *(--bp->wptr); + else + ctl = 0; + + /* + * send the block upstream + */ + if(bp->wptr > bp->rptr) + PUTNEXT(q, bp); + else + freeb(bp); + + /* + * handle the control character + */ + switch(ctl){ + case 0: + break; + + case ENQ: + urpstat.enqsr++; + queuectl(up, up->lastecho); + queuectl(up, ACK+up->iseq); + flushinput(up); + break; + + case CHECK: + queuectl(up, ACK+up->iseq); + break; + + case AINIT: + up->state &= ~INITING; + flushinput(up); + wakeup(&cp->kr); + break; + + case INIT0: + case INIT1: + queuectl(up, AINIT); + if(*bp->rptr == INIT1) + q->put = urpbiput; + initinput(up, 0); + break; + + case INITREQ: + initoutput(up, 0); + break; + + case BREAK: + break; + + case ACK+0: case ACK+1: case ACK+2: case ACK+3: + case ACK+4: case ACK+5: case ACK+6: case ACK+7: + case ECHO+0: case ECHO+1: case ECHO+2: case ECHO+3: + case ECHO+4: case ECHO+5: case ECHO+6: case ECHO+7: + rcvack(up, ctl); + break; + + case SEQ+0: case SEQ+1: case SEQ+2: case SEQ+3: + case SEQ+4: case SEQ+5: case SEQ+6: case SEQ+7: + /* + * acknowledge receipt + */ + ctl = ctl & 07; + if(q->next->len < Streamhi){ + queuectl(up, ECHO+ctl); + up->lastecho = ECHO+ctl; + wakeup(&cp->kr); + } + up->iseq = ctl; + break; + } +} + +/* + * block mode input. the last character in EVERY block is a control character. + */ +void +urpbiput(Queue *q, Block *bp, Rendez *rp) +{ + Urp *up; + int i, full; + Block *nbp; + + up = (Urp *)q->ptr; + if(bp->type != M_DATA){ + urpctliput(up, q, bp); + return; + } + + /* + * get the control character + */ + if(bp->wptr > bp->rptr) + ctl = *(--bp->wptr); + else + ctl = 0; + + /* + * take care of any block count(trx) + */ + while(bp->wptr > bp->rptr && up->trx){ + switch (up->trx) { + case 1: + case 2: + up->trbuf[up->trx++] = *bp->rptr++; + continue; + default: + up->trx = 0; + case 0: + break; + } + } + + /* + * queue the block + */ + if(bp->wptr > bp->rptr){ + if(q->len > up->iwindow){ + flushinput(up); + freeb(bp); + return; + } + putq(q, bp); + } else + freeb(bp); + + /* + * handle the control character + */ + switch(ctl){ + case 0: + break; + case ENQ: + urpstat.enqsr++; + queuectl(up, up->lastecho); + queuectl(up, ACK+up->iseq); + flushinput(up); + break; + + case CHECK: + queuectl(WR(q)->next, ACK+up->iseq); + break; + + case AINIT: + up->state &= ~INITING; + flushinput(up); + wakeup(&cp->kr); + break; + + case INIT0: + case INIT1: + queuectl(up, AINIT); + if(*bp->rptr == INIT0) + q->put = urpciput; + initinput(up, 0); + break; + + case INITREQ: + initoutput(up, 0); + break; + + case BREAK: + break; + + case BOT: + case BOTS: + case BOTM: + up->trx = 1; + up->trbuf[0] = ctl; + break; + + case REJ+0: case REJ+1: case REJ+2: case REJ+3: + case REJ+4: case REJ+5: case REJ+6: case REJ+7: + rcvack(up, ctl); + break; + + case ACK+0: case ACK+1: case ACK+2: case ACK+3: + case ACK+4: case ACK+5: case ACK+6: case ACK+7: + case ECHO+0: case ECHO+1: case ECHO+2: case ECHO+3: + case ECHO+4: case ECHO+5: case ECHO+6: case ECHO+7: + rcvack(up, ctl); + break; + + /* + * this case is extremely ugliferous + */ + case SEQ+0: case SEQ+1: case SEQ+2: case SEQ+3: + case SEQ+4: case SEQ+5: case SEQ+6: case SEQ+7: + i = ctl & 07; + if(up->trx != 3){ + urpstat.rjtrs++; + flushinput(up); + break; + } else if(q->len != up->trbuf[1] + (up->trbuf[2]<<8)){ + urpstat.rjpks++; + flushinput(up); + break; + } else if(i != ((up->iseq+1)&07))) { + urpstat.rjseq++; + flushinput(up); + break; + } + + /* + * send data upstream + */ + if(q->first) { + q->first->flags |= S_DELIM; + while(bp = getq(q)) + PUTNEXT(q, nbp); + } else { + bp = allocb(0); + bp->flag |= S_DELIM; + PUTNEXT(q, bp); + { + up->trx = 0; + + /* + * acknowledge receipt + */ + ctl = ctl & 07; + if(q->next->len < Streamhi){ + queuectl(up, ECHO+ctl); + up->lastecho = ECHO+ctl; + wakeup(&cp->kr); + } + up->iseq = ctl; + break; + } +} + +/* + * downstream control + */ +static void +urpctloput(Urp *up, Queue *q, Block *bp) +{ + int fields[2]; + int n; + int inwin=0, outwin=0; + + switch(bp->type){ + case M_CTL: + if(streamparse("init", bp)){ + switch(getfields(bp->rptr, fields, 2, ' ')){ + case 2: + inwin = strtoul(fields[1], 0, 0); + case 1: + outwin = strtoul(fields[0], 0, 0); + } + initinput(up, inwin); + initoutput(up, outwin); + freeb(bp); + return; + } + } + PUTNEXT(q, bp); +} + +/* + * accept data from writer + */ +urpoput(Queue *q, Block *bp) +{ + Urp *up; + + up = (Urp *)q->ptr; + + if(bp->type != M_DATA){ + urpctloput(up, q, bp); + return; + } + + urpstat.output + = bp->wptr - bp->rptr; + + for(;;){ + } +} + +/* + * wait for an AINIT + */ +void +urpopenwait(Urp *up, Queue *q) +{ + while((up->state&ISOPENING) && !(up->state&RCLOSE)) { + proc->state = Waiting; + up->proc = proc; + putctl1(q->next, M_RDATA, INIT1); + if((up->state&ISOPENING) == 0){ + up->proc = 0; + if(proc->state == Waiting){ + proc->state = Running; + return; + } + } + sched(); + up->proc = 0; + } +} + +/* + * wait till transmission is complete + */ +void +urpxmitwait(Urp *up, Queue *q) +{ + Block *bp; + int debug; + + debug = (q->flag&QDEBUG); + + up->timeout = 0; + while(!EMPTY(q) || up->WSWNX){ + /* + * clean up if the channel closed + */ + if (up->state & RCLOSE) { + while(bp = getq(q)) + freeb(bp); + up->WACK = up->WS = up->WNX; + } + /* + * free acked blocks + */ + urpfreeacked(up); + /* + * retransmit if requested + */ + if(up->state&REXMIT) + urprexmit(up, q); + /* + * fill up the window + */ + if(!EMPTY(q) && WINDOW(up)) + urpfillwindow(up, q); + /* + * ask other end for its status + */ + if(up->timeout){ + urpstat.enqsx++; + putctl1(q->next, M_RDATA, ENQ); + up->timeout = 0; + } + lock(up->olock); + if((up->state&RCLOSE) == 0 && up->WS! = up->WNX) { + proc->state = Waiting; + up->proc = proc; + unlock(up->olock); + sched(); + } else + unlock(up->olock); + } + urpfreeacked(up); + up->WS = up->WACK = up->WF = up->WNX = up->WNX&07; +} + +/* + * fill up the urp output window + */ +void +urpfillwindow(Urp *up, Queue *q) +{ + Block *bp, *xbp; + int debug; + + debug = (q->flag&QDEBUG); + + /* + * now process any thing that fits in the flow control window + */ + while (WINDOW(up)) { + bp = getq(q); + if (bp == NULL) + break; + /* force MAXBLOCK length segments */ + if (bp->rptr+up->maxblock < bp->wptr) { + xbp = allocb(0); + if (xbp == NULL) { + putbq(q, bp); + break; + } + xbp->rptr = bp->rptr; + bp->rptr + = up->maxblock; + xbp->wptr = bp->rptr; + putbq(q, bp); + bp = xbp; + } + /* + * put new block in the block array. if something is already + * there, it should be because we haven't gotten around to freeing + * it yet. If not, complain. + */ + if (up->xb[up->WNX&07]) { + urpfreeacked(up); + if (up->xb[up->WNX&07]) { + uprint(up, "urpfillwindow: overlap"); + freeb(up->xb[up->WNX&07]); + } + } + up->xb[up->WNX&07] = bp; + up->WNX++; + urpxmit(q, bp, up->WNX-1); + } +} + +/* + * Send out a message, with trailer. + */ +void +urpxmit(Queue *q, Block *bp, int seqno) +{ + Urp *up = (Urp *)q->ptr; + int size; + Block *xbp; + int debug; + + if (bp == NULL) { + print("null bp in urpxmit\n"); + return; + } + debug = (q->flag&QDEBUG); + size = bp->wptr - bp->rptr; + seqno & = 07; + /* send ptr to block, if non-empty */ + if (size) { + if ((xbp = allocb(0)) == NULL){ + print("can't xmit\n"); + return; + } + xbp->rptr = bp->rptr; + xbp->wptr = bp->wptr; + xbp->type = bp->type; + PUTNEXT(q, xbp); + } + /* send trailer */ + if ((xbp = allocb(3)) == NULL){ + print("can't xmit2\n"); + return; + } + xbp->type = M_RDATA; + *xbp->wptr++ = (bp->class&S_DELIM) ? BOT: BOTM; + *xbp->wptr++ = size; + *xbp->wptr++ = size >> 8; + PUTNEXT(q, xbp); + putctl1(q->next, M_RDATA, SEQ + seqno); + up->timer = DKPTIME; +} + +void +urprexmit(Urp *up, Queue *q) +{ + int i; + + for (i = up->WACK; iWNX; i++) { + urpxmit(q, up->xb[i&07], i); + urpstat.rxmit++; + } + up->state & = ~REXMIT; +} + +/* + * receive an acknowledgement + */ +static void +rcvack(Urp *up, int msg) +{ + int seqno; + int next; + + seqno = msg&07; + next = (seqno+1) & 0x7 + + lock(up); + if(BETWEEN(seqno, up->WACK, up->WNX)) + up->WACK = next; + + switch(msg & 0370){ + case ECHO: + up->timer = MSrexmit; /* push off ENQ timeout */ + if(BETWEEN(seqno, up->WS, up->WNX)){ + up->WS = next; + wakeup(&up->r); + } + break; + case REJ: + case ACK: + if(up->WACK == next){ + up->state |= REXMIT; + wakeup(&up->r); + } + break; + } + unlock(up); +} + +/* + * throw away any partially collected input + */ +static void +flushinput(Urp *up) +{ + Block *bp; + + while (bp = getq(up->rq)) + freeb(bp); + up->trx = 0; +} + +/* + * send a control character down stream + */ +static void +sendctl(Queue *q, int x) +{ + Block *bp; + + /* + * send anything queued + */ + while(bp = getq(q)) + PUTNEXT(q, bp); + + /* + * send the new byte + */ + bp = allocb(1); + *bp->wptr++ = x; + PUTNEXT(q, bp); +} + +/* + * queue a control character to be sent down stream + */ +static void +queuectl(Urp *up, int x) +{ + Block *bp; + Queue *q; + + q = up->wq; + bp = allocb(1); + *bp->wptr++ = x; + putq(q, bp); + wakeup(&up->r); +} + +/* + * initialize output + */ +static void +initoutput(Urp *up, int window) +{ + /* + * ack any outstanding blocks + */ + if(up->WSWNX) + urprack(up, ECHO+((up->WNX-1)&07)); + + /* + * set output window + */ + up->maxblock = window/4; + if(up->maxblock < 64) + up->maxblock = 64; + if(up->maxblock > Streamhi/4) + up->maxblock = Streamhi/4; + up->XW = 4; + + /* + * set sequence varialbles + */ + up->WS = 1; + up->WACK = 1; + up->WNX = 1; + + /* + * tell the other side we've inited + */ + up->state |= ISOPENING; + up->timer = MSrexmit; + sendctl(q->next, INIT1); +} + +/* + * initialize input + */ +static void +initinput(Urp *up, int window) +{ + /* + * restart all sequence parameters + */ + up->trx = 0; + up->iseq = 0; + up->lastecho = ECHO+0; + up->WF = 1; + flushinput(up); +} diff --git a/port/sysfile.c b/port/sysfile.c new file mode 100644 index 0000000000000000000000000000000000000000..f607a8852df8e24c591ad99a7e335c67adc86785 --- /dev/null +++ b/port/sysfile.c @@ -0,0 +1,508 @@ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "errno.h" +#include "fcall.h" + +/* + * The sys*() routines needn't poperror() as they return directly to syscall(). + */ + +int +newfd(void) +{ + int i; + + for(i=0; ifd[i] == 0){ + if(i > u->maxfd) + u->maxfd = i; + return i; + } + error(0, Enofd); +} + +Chan* +fdtochan(int fd, int mode) +{ + Chan *c; + + if(fd<0 || NFD<=fd || (c=u->fd[fd])==0) + error(0, Ebadfd); + if(mode<0 || c->mode == 2) + return c; + if((mode&16) && c->mode==0) + err: + error(0, Ebadusefd); + if((mode&~16) != c->mode) + goto err; + return c; +} + +int +openmode(ulong o) +{ + if(o >= (OTRUNC|OEXEC)) + Err: + error(0, Ebadarg); + o &= ~OTRUNC; + if(o > OEXEC) + goto Err; + if(o == OEXEC) + return OREAD; + return o; +} + +long +sysdup(ulong *arg) +{ + int fd; + Chan *c, *oc; + + /* + * Close after dup'ing, so date > #d/1 works + */ + c = fdtochan(arg[0], -1); + fd = arg[1]; + if(fd != -1) + oc = u->fd[fd]; + else{ + oc = 0; + fd = newfd(); + } + u->fd[fd] = c; + incref(c); + if(oc) + close(oc); + return fd; +} + +long +sysopen(ulong *arg) +{ + int fd; + Chan *c; + + openmode(arg[1]); /* error check only */ + fd = newfd(); + validaddr(arg[0], 1, 0); + c = namec((char*)arg[0], Aopen, arg[1], 0); + u->fd[fd] = c; + return fd; +} + +void +fdclose(int fd) +{ + int i; + + u->fd[fd] = 0; + if(fd == u->maxfd) + for(i=fd; --i>=0 && u->fd[i]==0; ) + u->maxfd = i; +} + +long +sysclose(ulong *arg) +{ + Chan *c; + + c = fdtochan(arg[0], -1); + close(c); + fdclose(arg[0]); + return 0; +} + +long +unionread(Chan *c, void *va, long n) +{ + Mount *mnt; + Chan *mc, *nc; + Pgrp *pg = u->p->pgrp; + long nr; + + mnt = c->mnt; + lock(pg); + if(c->mountid != mnt->mountid){ + print("unionread: changed underfoot?\n"); + unlock(pg); + return 0; + } + Again: + mc = mnt->c; + incref(mc); + unlock(pg); + if(waserror()){ + close(mc); + nexterror(); + } + nc = clone(mc, 0); + close(mc); + poperror(); + if(waserror()){ + close(nc); + nexterror(); + } + nc = (*devtab[nc->type].open)(nc, OREAD); + nc->offset = c->offset; + nr = (*devtab[nc->type].read)(nc, va, n); + close(nc); + poperror(); + if(nr > 0) + return nr; + /* + * Advance to next element + */ + lock(pg); + mnt = c->mnt; + if(c->mountid != mnt->mountid){ + print("unionread: changed underfoot?\n"); + unlock(pg); + return 0; + } + if(mnt->term){ + unlock(pg); + return 0; + } + mnt = mnt->next; + c->mnt = mnt; + c->mountid = mnt->mountid; + c->offset = 0; + goto Again; +} + +long +sysread(ulong *arg) +{ + Chan *c; + long n; + + c = fdtochan(arg[0], 0); + validaddr(arg[1], arg[2], 0); + qlock(c); + if(waserror()){ + qunlock(c); + nexterror(); + } + n = arg[2]; + if(c->qid&CHDIR){ + n -= n%DIRLEN; + if(c->offset%DIRLEN || n==0) + error(0, Ebaddirread); + } + if((c->qid&CHDIR) && c->flag&CMOUNT) + n = unionread(c, (void*)arg[1], n); + else + n = (*devtab[c->type].read)(c, (void*)arg[1], n); + c->offset += n; + qunlock(c); + return n; +} + +long +syswrite(ulong *arg) +{ + Chan *c; + long n; + + c = fdtochan(arg[0], 1); + validaddr(arg[1], arg[2], 0); + qlock(c); + if(waserror()){ + qunlock(c); + nexterror(); + } + if(c->qid & CHDIR) + error(0, Eisdir); + n = (*devtab[c->type].write)(c, (void*)arg[1], arg[2]); + c->offset += n; + qunlock(c); + return n; +} + +long +sysseek(ulong *arg) +{ + Chan *c; + char buf[DIRLEN]; + Dir dir; + long off; + + c = fdtochan(arg[0], -1); + if(c->qid & CHDIR) + error(0, Eisdir); + qlock(c); + if(waserror()){ + qunlock(c); + nexterror(); + } + switch(arg[2]){ + case 0: + c->offset = arg[1]; + break; + + case 1: + c->offset += (long)arg[1]; + break; + + case 2: + (*devtab[c->type].stat)(c, buf); + convM2D(buf, &dir); + c->offset = dir.length + (long)arg[1]; + break; + } + off = c->offset; + qunlock(c); + poperror(); + return off; +} + +long +sysfstat(ulong *arg) +{ + Chan *c; + long n; + + validaddr(arg[1], DIRLEN, 1); + evenaddr(arg[1]); + c = fdtochan(arg[0], -1); + (*devtab[c->type].stat)(c, (char*)arg[1]); + return 0; +} + +long +sysstat(ulong *arg) +{ + Chan *c; + long n; + + validaddr(arg[1], DIRLEN, 1); + evenaddr(arg[1]); + validaddr(arg[0], 1, 0); + c = namec((char*)arg[0], Aaccess, 0, 0); + if(waserror()){ + close(c); + nexterror(); + } + (*devtab[c->type].stat)(c, (char*)arg[1]); + poperror(); + close(c); + return 0; +} + +long +sysaccess(ulong *arg) +{ + Chan *c; + long mode; + + validaddr(arg[0], 1, 0); + c = namec((char*)arg[0], Aaccess, 0, 0); + mode = c->mode; + close(c); + /* BUG: check modes */ + return 0; +} + +long +syschdir(ulong *arg) +{ + Chan *c; + + validaddr(arg[0], 1, 0); + c = namec((char*)arg[0], Atodir, 0, 0); + close(u->dot); + u->dot = c; + return 0; +} + +long +bindmount(ulong *arg, int ismount) +{ + Chan *c0, *c1; + ulong flag; + long ret; + struct{ + Chan *chan; + char *spec; + }bogus; + + flag = arg[2]; + if(flag>MMASK || (flag&MORDER)==(MBEFORE|MAFTER)) + error(0, Ebadarg); + if(ismount){ + bogus.chan = fdtochan(arg[0], 2); +/*BUG: check validaddr for ALL of arg[3]!! */ + validaddr(arg[3], 1, 0); + bogus.spec = (char*)arg[3]; + ret = devno('M', 0); + c0 = (*devtab[ret].attach)((char*)&bogus); + }else{ + validaddr(arg[0], 1, 0); + c0 = namec((char*)arg[0], Aaccess, 0, 0); + } + if(waserror()){ + close(c0); + nexterror(); + } + validaddr(arg[1], 1, 0); + c1 = namec((char*)arg[1], Amount, 0, 0); + if(waserror()){ + close(c1); + nexterror(); + } + if((c0->qid^c1->qid) & CHDIR) + error(0, Ebadmount); + if(flag && !(c0->qid&CHDIR)) + error(0, Ebadmount); + ret = mount(c0, c1, flag); + close(c0); + close(c1); + if(ismount){ + close(bogus.chan); + fdclose(arg[0]); + } + return ret; +} + +long +sysbind(ulong *arg) +{ + return bindmount(arg, 0); +} + +long +sysmount(ulong *arg) +{ + return bindmount(arg, 1); +} + +long +syspipe(ulong *arg) +{ + int fd[2]; + Chan *c[2]; + Dev *d; + + validaddr(arg[0], 2*BY2WD, 1); + evenaddr(arg[0]); + d = &devtab[devno('|', 0)]; + c[0] = (*d->attach)(0); + c[1] = 0; + fd[0] = -1; + fd[1] = -1; + if(waserror()){ + close(c[0]); + if(c[1]) + close(c[1]); + if(fd[0] >= 0) + u->fd[fd[0]]=0; + if(fd[1] >= 0) + u->fd[fd[1]]=0; + nexterror(); + } + c[1] = (*d->clone)(c[0], 0); + c[0] = (*d->open)(c[0], ORDWR); + c[1] = (*d->open)(c[1], ORDWR); + c[0]->mode = 2; + c[1]->mode = 2; + c[0]->flag |= COPEN; + c[1]->flag |= COPEN; + fd[0] = newfd(); + u->fd[fd[0]] = c[0]; + fd[1] = newfd(); + u->fd[fd[1]] = c[1]; + ((long*)arg[0])[0] = fd[0]; + ((long*)arg[0])[1] = fd[1]; + poperror(); + return 0; +} + +long +syscreate(ulong *arg) +{ + int fd; + Chan *c; + + openmode(arg[1]); /* error check only */ + fd = newfd(); + validaddr(arg[0], 1, 0); + c = namec((char*)arg[0], Acreate, arg[1], arg[2]); + u->fd[fd] = c; + return fd; +} + +long +sysuserstr(ulong *arg) +{ + Error err; + char buf[NAMELEN]; + + validaddr(arg[0], sizeof(Error), 0); + validaddr(arg[1], NAMELEN, 1); + err = *(Error*)arg[0]; + err.type = devno(err.type, 1); + if(err.type == -1) + strcpy((char*)arg[1], "*gok*"); + else{ + (*devtab[err.type].userstr)(&err, buf); + memcpy((char*)arg[1], buf, sizeof buf); + } + return 0; +} + +long +sysremove(ulong *arg) +{ + Chan *c; + + validaddr(arg[0], 1, 0); + c = namec((char*)arg[0], Aaccess, 0, 0); + if(waserror()){ + close(c); + nexterror(); + } + (*devtab[c->type].remove)(c); + /* + * Remove clunks the fid, but we need to recover the Chan + * so fake it up. rootclose() is known to be a nop. + */ + c->type = 0; + close(c); + return 0; +} + +long +syswstat(ulong *arg) +{ + Chan *c; + long n; + + validaddr(arg[1], DIRLEN, 0); + evenaddr(arg[1]); + validaddr(arg[0], 1, 0); + c = namec((char*)arg[0], Aaccess, 0, 0); + if(waserror()){ + close(c); + nexterror(); + } + (*devtab[c->type].wstat)(c, (char*)arg[1]); + poperror(); + close(c); + return 0; +} + +long +sysfwstat(ulong *arg) +{ + Chan *c; + long n; + + validaddr(arg[1], DIRLEN, 0); + evenaddr(arg[1]); + c = fdtochan(arg[0], -1); + (*devtab[c->type].wstat)(c, (char*)arg[1]); + return 0; +} diff --git a/port/sysproc.c b/port/sysproc.c new file mode 100644 index 0000000000000000000000000000000000000000..d75c8cec6e8456ab2ed009a01e63ecb12ded3d9b --- /dev/null +++ b/port/sysproc.c @@ -0,0 +1,501 @@ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "ureg.h" +#include "errno.h" + +#include + +int shargs(char*, int, char**); + +long +sysr1(ulong *arg) +{ + print("[%d] r1 = %d\n", u->p->pid, arg[0]); + return 0; +} + +long +sysfork(ulong *arg) +{ + Proc *p; + Seg *s; + Page *np, *op; + ulong usp, upa, pid; + Chan *c; + Orig *o; + int n, on, i; + int lastvar; /* used to compute stack address */ + + /* + * Kernel stack + */ + p = newproc(); + p->upage = newpage(1, 0, USERADDR|(p->pid&0xFFFF)); + upa = p->upage->pa|KZERO; + /* + * Save time: only copy u-> data and useful stack + */ + memcpy((void*)upa, u, sizeof(User)); + n = USERADDR+BY2PG - (ulong)&lastvar; + n = (n+32) & ~(BY2WD-1); /* be safe & word align */ + memcpy((void*)(upa+BY2PG-n), (void*)((u->p->upage->pa|KZERO)+BY2PG-n), n); + ((User *)upa)->p = p; + + /* + * User stack + */ + p->seg[SSEG] = u->p->seg[SSEG]; + s = &p->seg[SSEG]; + s->proc = p; + on = (s->maxva-s->minva)>>PGSHIFT; + usp = ((Ureg*)UREGADDR)->sp; + if(usp >= USTKTOP) + panic("fork bad usp %lux", usp); + if(usp < u->p->seg[SSEG].minva) + s->minva = u->p->seg[SSEG].minva; + else + s->minva = usp & ~(BY2PG-1); + 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); + lock(s->o); + /* + * Only part of last stack page + */ + for(i=0; ip->seg[SSEG].o->pte[i+(on-n)].page; + if(op){ + np = newpage(1, s->o, op->va); + p->seg[SSEG].o->pte[i].page = np; + if(i == 0){ /* only part of last stack page */ + memset((void*)(np->pa|KZERO), 0, usp); + memcpy((void*)((np->pa+usp)|KZERO), + (void*)((op->pa+usp)|KZERO), BY2PG-usp); + }else /* all of higher pages */ + memcpy((void*)(np->pa|KZERO), (void*)(op->pa|KZERO), BY2PG); + } + } + unlock(s->o); + /* + * Duplicate segments + */ + for(s=&u->p->seg[0], n=0; no == 0) + continue; + p->seg[n] = *s; + p->seg[n].proc = p; + o = s->o; + lock(o); + o->nproc++; + if(s->mod) + forkmod(s, &p->seg[n], p); + unlock(o); + } + /* + * Refs + */ + incref(u->dot); + for(n=0; n<=u->maxfd; n++) + if(c = u->fd[n]) /* assign = */ + incref(c); + /* + * Sched + */ + if(setlabel(&p->sched)){ + u->p = p; + p->state = Running; + p->mach = m; + m->proc = p; + spllo(); + return 0; + } + p->parent = u->p; + p->parentpid = u->p->pid; + p->pgrp = u->p->pgrp; + incref(p->pgrp); + u->p->nchild++; + pid = p->pid; + memset(p->time, 0, sizeof(p->time)); + p->time[TReal] = MACHP(0)->ticks; + memcpy(p->text, u->p->text, NAMELEN); + ready(p); + flushmmu(); + return pid; +} + +long +sysexec(ulong *arg) +{ + Proc *p; + Seg *s; + ulong l, t, d, b, v; + int i; + Chan *tc; + Orig *o; + char **argv, **argp; + char *a, *charp, *file; + char *progarg[sizeof(Exec)/2+1], elem[NAMELEN]; + ulong ssize, spage, nargs, nbytes, n; + ulong *sp; + int indir; + Exec exec; + char line[sizeof(Exec)]; + + p = u->p; + validaddr(arg[0], 1, 0); + file = (char*)arg[0]; + indir = 0; + Header: + tc = namec(file, Aopen, OEXEC, 0); + if(waserror()){ + close(tc); + nexterror(); + } + if(!indir) + strcpy(elem, u->elem); + n = (*devtab[tc->type].read)(tc, &exec, sizeof(Exec)); + if(n < 2) + Err: + error(0, Ebadexec); + if(n==sizeof(Exec) && exec.magic==V_MAGIC){ + if((exec.text&KZERO) + || (ulong)exec.entry < UTZERO+sizeof(Exec) + || (ulong)exec.entry >= UTZERO+sizeof(Exec)+exec.text) + goto Err; + goto Binary; + } + + /* + * Process #! /bin/sh args ... + */ + memcpy(line, &exec, sizeof(Exec)); + if(indir || line[0]!='#' || line[1]!='!') + goto Err; + n = shargs(line, n, progarg); + if(n == 0) + goto Err; + indir = 1; + /* + * First arg becomes complete file name + */ + progarg[n++] = file; + progarg[n] = 0; + validaddr(arg[1], BY2WD, 1); + arg[1] += BY2WD; + file = progarg[0]; + progarg[0] = elem; + close(tc); + poperror(); + goto Header; + + Binary: + t = (UTZERO+sizeof(Exec)+exec.text+(BY2PG-1)) & ~(BY2PG-1); + /* + * Last partial page of data goes into BSS. + */ + d = (t + exec.data) & ~(BY2PG-1); + b = (t + exec.data + exec.bss + (BY2PG-1)) & ~(BY2PG-1); + if((t|d|b) & KZERO) + error(0, Ebadexec); + + /* + * Args: pass 1: count + */ + nbytes = 0; + nargs = 0; + if(indir){ + argp = progarg; + while(*argp){ + a = *argp++; + nbytes += strlen(a) + 1; + nargs++; + } + } + evenaddr(arg[1]); + argp = (char**)arg[1]; + validaddr((ulong)argp, BY2WD, 0); + while(*argp){ + a = *argp++; + if(((ulong)argp&(BY2PG-1)) < BY2WD) + validaddr((ulong)argp, BY2WD, 0); + validaddr((ulong)a, 1, 0); + nbytes += (vmemchr(a, 0, 0xFFFFFFFF) - a) + 1; + nargs++; + } + ssize = BY2WD*(nargs+1) + ((nbytes+(BY2WD-1)) & ~(BY2WD-1)); + spage = (ssize+(BY2PG-1)) >> PGSHIFT; + + /* + * Build the stack segment, putting it in kernel virtual for the moment + */ + s = &p->seg[ESEG]; + s->proc = p; + s->o = neworig(TSTKTOP-(spage<minva = s->o->va; + s->maxva = TSTKTOP; + + /* + * Args: pass 2: assemble; the pages will be faulted in + */ + argv = (char**)(TSTKTOP - ssize); + charp = (char*)(TSTKTOP - nbytes); + if(indir) + argp = progarg; + else + argp = (char**)arg[1]; + for(i=0; itext, elem, NAMELEN); + + /* + * Committed. Free old memory + */ + freesegs(ESEG); + + /* + * Text. Shared. + */ + s = &p->seg[TSEG]; + s->proc = p; + o = lookorig(UTZERO, (t-UTZERO)>>PGSHIFT, OCACHED, tc); + if(o == 0){ + o = neworig(UTZERO, (t-UTZERO)>>PGSHIFT, OCACHED, tc); + o->minca = 0; + o->maxca = sizeof(Exec)+exec.text; + } + s->o = o; + s->minva = UTZERO; + s->maxva = t; + s->mod = 0; + + /* + * Data. Shared. + */ + s = &p->seg[DSEG]; + s->proc = p; + o = lookorig(t, (d-t)>>PGSHIFT, OWRPERM|OPURE|OCACHED, tc); + if(o == 0){ + o = neworig(t, (d-t)>>PGSHIFT, OWRPERM|OPURE|OCACHED, tc); + o->minca = p->seg[TSEG].o->maxca; + o->maxca = o->minca + (exec.data & ~(BY2PG-1)); + } + s->o = o; + s->minva = t; + s->maxva = d; + s->mod = 0; + + /* + * BSS. Created afresh, starting with last page of data. + * BUG: should pick up the last page of data, which should be cached in the + * data segment. + */ + s = &p->seg[BSEG]; + s->proc = p; + o = neworig(d, (b-d)>>PGSHIFT, OWRPERM, tc); + o->minca = p->seg[DSEG].o->maxca; + o->maxca = o->minca + (exec.data & (BY2PG-1)); + s->o = o; + s->minva = d; + s->maxva = b; + s->mod = 0; + + close(tc); + + /* + * Move the stack + */ + s = &p->seg[SSEG]; + *s = p->seg[ESEG]; + p->seg[ESEG].o = 0; + o = s->o; + o->va += (USTKTOP-TSTKTOP); + s->minva = o->va; + s->maxva = USTKTOP; + lock(o); + for(i=0; inpte; i++) + o->pte[i].page->va += (USTKTOP-TSTKTOP); + unlock(o); + + flushmmu(); + ((Ureg*)UREGADDR)->pc = exec.entry - 4; + sp = (ulong*)(USTKTOP - ssize); + *--sp = nargs; + ((Ureg*)UREGADDR)->sp = (ulong)sp; + lock(&p->debug); + u->nnote = 0; + u->notify = 0; + u->notified = 0; + unlock(&p->debug); + return 0; +} + +int +shargs(char *s, int n, char **ap) +{ + int i; + + s += 2, n -= 2; /* skip #! */ + for(i=0; s[i]!='\n'; i++) + if(i == n-1) + return 0; + s[i] = 0; + *ap = 0; + i = 0; + for(;;){ + while(*s==' ' || *s=='\t') + s++; + if(*s == 0) + break; + i++; + *ap++ = s; + *ap = 0; + while(*s && *s!=' ' && *s!='\t') + s++; + if(*s == 0) + break; + else + *s++ = 0; + } + return i; +} + +int +return0(void *a) +{ + return 0; +} + +long +syssleep(ulong *arg) +{ + int ms; + + tsleep(&u->p->sleep, return0, 0, arg[0]); + return 0; +} + + +long +sysexits(ulong *arg) +{ + char *status; + + status = (char*)arg[0]; + if(status){ + if(waserror()) + status = "invalid exit string"; + else{ + validaddr((ulong)status, 1, 0); + vmemchr(status, 0, ERRLEN); + } + } + pexit(status, 1); +} + +long +syswait(ulong *arg) +{ + if(arg[0]){ + validaddr(arg[0], sizeof(Waitmsg), 1); + evenaddr(arg[0]); + } + return pwait((Waitmsg*)arg[0]); +} + +long +syslasterr(ulong *arg) +{ + Error *e; + + validaddr(arg[0], sizeof u->error, 1); + evenaddr(arg[0]); + e = (Error *)arg[0]; + memcpy(e, &u->error, sizeof u->error); + memset(&u->error, 0, sizeof u->error); + e->type = devchar[e->type]; + return 0; +} + +long +syserrstr(ulong *arg) +{ + Error *e, err; + char buf[ERRLEN]; + + validaddr(arg[1], ERRLEN, 1); + e = &err; + if(arg[0]){ + validaddr(arg[0], sizeof u->error, 0); + memcpy(e, (Error*)arg[0], sizeof(Error)); + e->type = devno(e->type, 1); + if(e->type == -1){ + e->type = 0; + e->code = Egreg+1; /* -> "no such error" */ + } + }else{ + memcpy(e, &u->error, sizeof(Error)); + memset(&u->error, 0, sizeof(Error)); + } + (*devtab[e->type].errstr)(e, buf); + memcpy((char*)arg[1], buf, sizeof buf); + return 0; +} + +long +sysforkpgrp(ulong *arg) +{ + Pgrp *pg; + + pg = newpgrp(); + if(waserror()){ + closepgrp(pg); + nexterror(); + } + if(arg[0] == 0) + pgrpcpy(pg, u->p->pgrp); + closepgrp(u->p->pgrp); + u->p->pgrp = pg; + return pg->pgrpid; +} + +long +sysnotify(ulong *arg) +{ + validaddr(arg[0], sizeof(ulong), 0); + u->notify = (int(*)(void*, char*))(arg[0]); + return 0; +} + +long +sysnoted(ulong *arg) +{ + if(u->notified == 0) + error(0, Egreg); + return 0; +} + +/* + * Temporary; should be replaced by a generalized segment control operator + */ +long +sysbrk_(ulong *arg) +{ + if(segaddr(&u->p->seg[BSEG], u->p->seg[BSEG].minva, arg[0]) == 0) + error(0, Esegaddr); + return 0; +} diff --git a/power/boot.c b/power/boot.c new file mode 100644 index 0000000000000000000000000000000000000000..10a964c21ba26fc46b7e245e591e36ce8609f2ac --- /dev/null +++ b/power/boot.c @@ -0,0 +1,202 @@ +#include +#include + +#include + +Fcall hdr; +char buf[100]; +char srv[100]; + +void error(char *); + +typedef +struct address { + char *name; + char *cmd; +} Address; + +Address addr[] = { + { "ross", "connect 020701005eff" }, + { "bootes", "connect 080069020205" }, + { "helix", "connect 080069020427" }, + { "spindle", "connect 0800690202df" }, + { "r70", "connect 08002b04265d" }, + { "bitbootes", "bitconnect" }, + { 0 } +}; + +#define DEFUSER "bootes" + +char * +lookup(char *arg) +{ + Address *a; + + if(strcmp(arg, "?")==0 || strcmp(arg, "help")==0){ + for(a = addr; a->name; a++) + print("%s\n", a->name); + return 0; + } + for(a = addr; a->name; a++){ + if(strcmp(a->name, arg) == 0) + return a->cmd; + } + return 0; +} + +main(int argc, char *argv[]) +{ + int cfd, fd, n, fu, f; + char buf[NAMELEN]; + char *scmd; + + open("#c/cons", 0); + open("#c/cons", 1); + open("#c/cons", 1); + + /* + * get server + */ + do{ + do{ + print("server[%s]: ", addr[0].name); + n = read(0, srv, sizeof srv); + }while(n==0); + if(n < 0) + error("can't read #c/cons; please reboot"); + if(n == 1) + strcpy(srv, addr[0].name); + else + srv[n-1] = 0; + scmd = lookup(srv); + }while(scmd == 0); + + /* + * get user. if the user typed cr to the server question, skip + * the user question and just use the default. + */ + if(n != 1){ + do{ + print("user[%s]: ", DEFUSER); + n = read(0, buf, sizeof buf); + }while(n==0); + if(n < 0) + error("can't read #c/cons; please reboot"); + if(n == 1) + strcpy(buf, DEFUSER); + else + buf[n-1] = 0; + }else + strcpy(buf, DEFUSER); + + fu = create("#c/user", 1, 0600); + if(fu < 0) + error("#c/user"); + n = strlen(buf); + if(write(fu, buf, n) != n) + error("user write"); + close(fu); + + if(strcmp(scmd, "bitconnect") == 0){ + fd = open("#b/bit", ORDWR); + if(fd < 0) + error("opening #b/bit"); + goto Mesg; + } + + /* + * grab a lance channel, make it recognize ether type 0x900, + * and push the nonet ethernet multiplexor onto it. + */ + cfd = open("#l/1/ctl", 2); + if(cfd < 0) + error("opening #l/1/ctl"); + if(write(cfd, "connect 0x900", sizeof("connect 0x900")-1)<0) + error("connect 0x900"); + if(write(cfd, "push noether", sizeof("push noether")-1)<0) + error("push noether"); + + /* + * grab a nonet channel and call up the ross file server + */ + fd = open("#n/1/data", 2); + if(fd < 0) + error("opening #n/1/data"); + cfd = open("#n/1/ctl", 2); + if(cfd < 0) + error("opening #n/1/ctl"); + if(write(cfd, scmd, strlen(scmd))<0) + error(scmd); + + Mesg: + print("nop..."); + hdr.type = Tnop; + n = convS2M(&hdr, buf); + if(write(fd, buf, n) != n) + error("write nop"); + n = read(fd, buf, sizeof buf); + if(n <= 0) + error("read nop"); + if(convM2S(buf, &hdr, n) == 0) { + print("n = %d; buf = %.2x %.2x %.2x %.2x\n", + n, buf[0], buf[1], buf[2], buf[3]); + error("format nop"); + } + if(hdr.type != Rnop) + error("not Rnop"); + + print("session..."); + hdr.type = Tsession; + hdr.lang = 'v'; + n = convS2M(&hdr, buf); + if(write(fd, buf, n) != n) + error("write session"); + n = read(fd, buf, sizeof buf); + if(n <= 0) + error("read session"); + if(convM2S(buf, &hdr, n) == 0) + error("format session"); + if(hdr.type != Rsession) + error("not Rsession"); + if(hdr.err){ + print("error %d;", hdr.err); + error("remote error"); + } + + print("post..."); + sprint(buf, "#s/%s", srv); + f = create(buf, 1, 0666); + if(f < 0) + error("create"); + sprint(buf, "%d", fd); + if(write(f, buf, strlen(buf)) != strlen(buf)) + error("write"); + close(f); + sprint(buf, "#s/%s", srv); + f = create("#s/boot", 1, 0666); + if(f < 0) + error("create"); + sprint(buf, "%d", fd); + if(write(f, buf, strlen(buf)) != strlen(buf)) + error("write"); + close(f); + + print("mount..."); + if(bind("/", "/", MREPL) < 0) + error("bind"); + if(mount(fd, "/", MAFTER|MCREATE, "") < 0) + error("mount"); + print("success\n"); + execl("/mips/init", "init", 0); + error("/mips/init"); +} + +void +error(char *s) +{ + char buf[64]; + + errstr(0, buf); + fprint(2, "boot: %s: %s\n", s, buf); + exits(0); +} diff --git a/power/boot.h b/power/boot.h new file mode 100644 index 0000000000000000000000000000000000000000..fb42123b00ecc40df4544584b39f5b564b2eaa5d --- /dev/null +++ b/power/boot.h @@ -0,0 +1,4350 @@ +ulong bootcode[]={ + 0x00000407, + 0x00003ed0, + 0x000004f0, + 0x00000198, + 0x00000000, + 0x00001020, + 0x00000000, + 0x00000000, + 0x23bdffec, + 0xafbf0000, + 0x3c1e0000, + 0x37decffe, + 0x8fa10014, + 0x23a20018, + 0xafa10004, + 0x0c000458, + 0xafa20008, + 0x0c0006a5, + 0xafa10004, + 0x08000411, + 0x00000027, + 0x23bdfff0, + 0xafbf0000, + 0x8fa20014, + 0x23c38262, + 0xafa20004, + 0x0c000c37, + 0xafa30008, + 0x10200025, + 0x00000027, + 0x8fa20014, + 0x23c38264, + 0xafa20004, + 0x0c000c37, + 0xafa30008, + 0x1020001e, + 0x00000027, + 0x23c4806a, + 0x8c820000, + 0x00000027, + 0x10400015, + 0x00000027, + 0xafa4000c, + 0x8c820000, + 0x00000027, + 0xafa20004, + 0x8fa30014, + 0x0c000c37, + 0xafa30008, + 0x8fa4000c, + 0x14200006, + 0x00000027, + 0x8c810004, + 0x8fa20000, + 0x00000027, + 0x00400008, + 0x23bd0010, + 0x24840008, + 0x8c820000, + 0x00000027, + 0x1440ffed, + 0x00000027, + 0x8fa20000, + 0x23bd0010, + 0x00400008, + 0x00000825, + 0x23c4806a, + 0x8c810000, + 0x00000027, + 0x1020000e, + 0x00000027, + 0x23c28269, + 0xafa20004, + 0xafa4000c, + 0x8c810000, + 0x0c0006d0, + 0xafa10008, + 0x8fa2000c, + 0x00000027, + 0x24440008, + 0x8c810000, + 0x00000027, + 0x1420fff4, + 0x00000027, + 0x8fa20000, + 0x23bd0010, + 0x00400008, + 0x00000825, + 0x23bdffb0, + 0xafbf0000, + 0x23c2826d, + 0xafa20004, + 0x0c00134b, + 0xafa00008, + 0x23c18275, + 0xafa10004, + 0x20020001, + 0x0c00134b, + 0xafa20008, + 0x23c1827d, + 0xafa10004, + 0x20020001, + 0x0c00134b, + 0xafa20008, + 0x23c18285, + 0xafa10004, + 0x8fc2806a, + 0x0c0006d0, + 0xafa20008, + 0xafa00004, + 0x23c28622, + 0xafa20008, + 0x20030064, + 0x0c001350, + 0xafa3000c, + 0x00012025, + 0x14800003, + 0x00000027, + 0x08000468, + 0x00000027, + 0x04810006, + 0xafa40044, + 0x23c18292, + 0x0c000664, + 0xafa10004, + 0x8fa40044, + 0x00000027, + 0x20010001, + 0x148101df, + 0x00000027, + 0x23c28622, + 0xafa20004, + 0x8fc1806a, + 0x0c000c4d, + 0xafa10008, + 0x23c18622, + 0x0c000415, + 0xafa10004, + 0x00012025, + 0x14800003, + 0xafa4001c, + 0x08000468, + 0x00000027, + 0x8fa10044, + 0x20020001, + 0x102201c7, + 0x00000027, + 0x23c282b4, + 0xafa20004, + 0x23c182bf, + 0x0c0006d0, + 0xafa10008, + 0xafa00004, + 0x23a10020, + 0xafa10008, + 0x2003001c, + 0x0c001350, + 0xafa3000c, + 0x00012025, + 0x14800003, + 0x00000027, + 0x08000493, + 0x00000027, + 0x04810006, + 0xafa40044, + 0x23c282c6, + 0x0c000664, + 0xafa20004, + 0x8fa40044, + 0x00000027, + 0x20020001, + 0x148201a9, + 0x00000027, + 0x23a10020, + 0xafa10004, + 0x23c282e8, + 0x0c000c4d, + 0xafa20008, + 0x23c282f6, + 0xafa20004, + 0x20030001, + 0xafa30008, + 0x20020180, + 0x0c001337, + 0xafa2000c, + 0x04210004, + 0xafa10040, + 0x23c182fe, + 0x0c000664, + 0xafa10004, + 0x23a10020, + 0x0c000c5a, + 0xafa10004, + 0x8fa20040, + 0x23a30020, + 0xafa20004, + 0xafa30008, + 0xafa10044, + 0x0c001355, + 0xafa1000c, + 0x8fa30044, + 0x00000027, + 0x10230004, + 0x00000027, + 0x23c18306, + 0x0c000664, + 0xafa10004, + 0x8fa20040, + 0x0c001332, + 0xafa20004, + 0x8fa2001c, + 0x23c38311, + 0xafa20004, + 0x0c000c37, + 0xafa30008, + 0x14200132, + 0x20040002, + 0x23c2831c, + 0xafa20004, + 0x0c00134b, + 0xafa40008, + 0x04210004, + 0xafa10048, + 0x23c18323, + 0x0c000664, + 0xafa10004, + 0x23c283b8, + 0x0c0006d0, + 0xafa20004, + 0xa3c085da, + 0x23c285da, + 0xafa20004, + 0x23a30020, + 0x0c000c75, + 0xafa30008, + 0x00012025, + 0x8fa10048, + 0x23a30020, + 0xafa10004, + 0xafa30008, + 0xafa40044, + 0x0c001355, + 0xafa4000c, + 0x8fa30044, + 0x00000027, + 0x10230004, + 0x00000027, + 0x23c183bf, + 0x0c000664, + 0xafa10004, + 0x8fa10048, + 0x23a30020, + 0xafa10004, + 0xafa30008, + 0x2001001c, + 0x0c001350, + 0xafa1000c, + 0xafa10044, + 0x1c200006, + 0x00012025, + 0x23c283c9, + 0x0c000664, + 0xafa20004, + 0x8fa40044, + 0x00000027, + 0x23a20020, + 0xafa20004, + 0x23c385da, + 0xafa30008, + 0x0c001012, + 0xafa4000c, + 0x14200015, + 0x00000027, + 0x23c183d2, + 0xafa10004, + 0x8fa20044, + 0x00000027, + 0xafa20008, + 0x83a10020, + 0x00000027, + 0xafa1000c, + 0x83a20021, + 0x00000027, + 0xafa20010, + 0x83a10022, + 0x00000027, + 0xafa10014, + 0x83a20023, + 0x0c0006d0, + 0xafa20018, + 0x23c183f5, + 0x0c000664, + 0xafa10004, + 0x83c285da, + 0x20010001, + 0x10410004, + 0x00000027, + 0x23c28400, + 0x0c000664, + 0xafa20004, + 0x23c18409, + 0x0c0006d0, + 0xafa10004, + 0x20020002, + 0xa3c285da, + 0x20010076, + 0xa3c185e6, + 0x23c185da, + 0xafa10004, + 0x23a30020, + 0x0c000c75, + 0xafa30008, + 0x8fa20048, + 0x23a30020, + 0xafa20004, + 0xafa30008, + 0xafa10044, + 0x0c001355, + 0xafa1000c, + 0x8fa30044, + 0x00000027, + 0x10230004, + 0x00000027, + 0x23c18414, + 0x0c000664, + 0xafa10004, + 0x8fa10048, + 0x23a30020, + 0xafa10004, + 0xafa30008, + 0x2001001c, + 0x0c001350, + 0xafa1000c, + 0xafa10044, + 0x1c200006, + 0x00012025, + 0x23c28422, + 0x0c000664, + 0xafa20004, + 0x8fa40044, + 0x00000027, + 0x23a20020, + 0xafa20004, + 0x23c385da, + 0xafa30008, + 0x0c001012, + 0xafa4000c, + 0x14200004, + 0x00000027, + 0x23c1842f, + 0x0c000664, + 0xafa10004, + 0x83c285da, + 0x20010003, + 0x10410004, + 0x00000027, + 0x23c2843e, + 0x0c000664, + 0xafa20004, + 0x87c185de, + 0x00000027, + 0x10200009, + 0x00000027, + 0x23c2844b, + 0xafa20004, + 0x87c185de, + 0x0c0006d0, + 0xafa10008, + 0x23c28455, + 0x0c000664, + 0xafa20004, + 0x23c18462, + 0x0c0006d0, + 0xafa10004, + 0x23a20020, + 0xafa20004, + 0x23c1846a, + 0xafa10008, + 0x23c28622, + 0x0c00071b, + 0xafa2000c, + 0x23a20020, + 0xafa20004, + 0x20030001, + 0xafa30008, + 0x200201b6, + 0x0c001337, + 0xafa2000c, + 0x04210004, + 0xafa1003c, + 0x23c18470, + 0x0c000664, + 0xafa10004, + 0x23a20020, + 0xafa20004, + 0x23c18477, + 0xafa10008, + 0x8fa20048, + 0x0c00071b, + 0xafa2000c, + 0x23a30020, + 0x0c000c5a, + 0xafa30004, + 0xafa10018, + 0x23a30020, + 0x0c000c5a, + 0xafa30004, + 0xafa10014, + 0x8fa3003c, + 0x23a10020, + 0xafa30004, + 0xafa10008, + 0x8fa30014, + 0x0c001355, + 0xafa3000c, + 0x00011025, + 0x8fa10018, + 0x00000027, + 0x10410004, + 0x00000027, + 0x23c2847a, + 0x0c000664, + 0xafa20004, + 0x8fa1003c, + 0x0c001332, + 0xafa10004, + 0x23a20020, + 0xafa20004, + 0x23c18480, + 0xafa10008, + 0x23c28622, + 0x0c00071b, + 0xafa2000c, + 0x23c28486, + 0xafa20004, + 0x20030001, + 0xafa30008, + 0x200201b6, + 0x0c001337, + 0xafa2000c, + 0x04210004, + 0xafa1003c, + 0x23c1848e, + 0x0c000664, + 0xafa10004, + 0x23a20020, + 0xafa20004, + 0x23c18495, + 0xafa10008, + 0x8fa20048, + 0x0c00071b, + 0xafa2000c, + 0x23a30020, + 0x0c000c5a, + 0xafa30004, + 0xafa10018, + 0x23a30020, + 0x0c000c5a, + 0xafa30004, + 0xafa10014, + 0x8fa3003c, + 0x23a10020, + 0xafa30004, + 0xafa10008, + 0x8fa30014, + 0x0c001355, + 0xafa3000c, + 0x00011025, + 0x8fa10018, + 0x00000027, + 0x10410004, + 0x00000027, + 0x23c28498, + 0x0c000664, + 0xafa20004, + 0x8fa1003c, + 0x0c001332, + 0xafa10004, + 0x23c2849e, + 0x0c0006d0, + 0xafa20004, + 0x23c284a7, + 0xafa20004, + 0x23c384a9, + 0xafa30008, + 0x0c00132d, + 0xafa0000c, + 0x04210004, + 0x00000027, + 0x23c184ab, + 0x0c000664, + 0xafa10004, + 0x8fa10048, + 0x23c384b0, + 0xafa10004, + 0xafa30008, + 0x20010006, + 0xafa1000c, + 0x23c384b2, + 0x0c001346, + 0xafa30010, + 0x04210004, + 0x00000027, + 0x23c184b3, + 0x0c000664, + 0xafa10004, + 0x23c284b9, + 0x0c0006d0, + 0xafa20004, + 0x23c184c2, + 0xafa10004, + 0x23c284cd, + 0xafa20008, + 0x0c000c69, + 0xafa0000c, + 0x23c184d2, + 0x0c000664, + 0xafa10004, + 0x8fa20000, + 0x00000027, + 0x00400008, + 0x23bd0050, + 0x23c18332, + 0xafa10004, + 0x0c00134b, + 0xafa40008, + 0xafa1004c, + 0x04210006, + 0x00012025, + 0x23c2833b, + 0x0c000664, + 0xafa20004, + 0x8fa4004c, + 0x00000027, + 0xafa40004, + 0x23c3834c, + 0xafa30008, + 0x2002000d, + 0x0c001355, + 0xafa2000c, + 0x04210004, + 0x00000027, + 0x23c1835a, + 0x0c000664, + 0xafa10004, + 0x8fa1004c, + 0x23c38368, + 0xafa10004, + 0xafa30008, + 0x2001000c, + 0x0c001355, + 0xafa1000c, + 0x04210004, + 0x00000027, + 0x23c28375, + 0x0c000664, + 0xafa20004, + 0x23c28382, + 0xafa20004, + 0x20030002, + 0x0c00134b, + 0xafa30008, + 0x04210004, + 0xafa10048, + 0x23c1838c, + 0x0c000664, + 0xafa10004, + 0x23c1839e, + 0xafa10004, + 0x20030002, + 0x0c00134b, + 0xafa30008, + 0x04210004, + 0xafa1004c, + 0x23c283a7, + 0x0c000664, + 0xafa20004, + 0x8fa3001c, + 0x0c000c5a, + 0xafa30004, + 0xafa10018, + 0x8fa3004c, + 0x00000027, + 0xafa30004, + 0x8fa2001c, + 0x00000027, + 0xafa20008, + 0x8fa30018, + 0x0c001355, + 0xafa3000c, + 0x0421fe93, + 0x00000027, + 0x8fa1001c, + 0x0c000664, + 0xafa10004, + 0x080004e2, + 0x00000027, + 0x23a10020, + 0x00810821, + 0x080004b2, + 0xa020ffff, + 0x23a10020, + 0xafa10004, + 0x23c282ef, + 0x0c000c4d, + 0xafa20008, + 0x080004b2, + 0x00000027, + 0x23c28622, + 0x00821021, + 0x08000487, + 0xa040ffff, + 0x23bdffac, + 0xafbf0000, + 0xafa00004, + 0x23a20014, + 0x0c00133c, + 0xafa20008, + 0x20010002, + 0xafa10004, + 0x23c284dd, + 0xafa20008, + 0x8fa10058, + 0x23a20014, + 0xafa1000c, + 0x0c0006f6, + 0xafa20010, + 0x0c0006b4, + 0xafa00004, + 0x8fa20000, + 0x00000027, + 0x00400008, + 0x23bd0054, + 0x23bdfff8, + 0x00002025, + 0x28810021, + 0x10200011, + 0x23c584f2, + 0x00040880, + 0x00250821, + 0x8c210000, + 0x00000027, + 0x14200008, + 0x00000027, + 0x00041080, + 0x8fa3000c, + 0x00451021, + 0x20010001, + 0x23bd0008, + 0x03e00008, + 0xac430000, + 0x28810020, + 0x1420fff1, + 0x24840001, + 0x23bd0008, + 0x03e00008, + 0x00000825, + 0x23bdfff8, + 0x8fa5000c, + 0x00001825, + 0x28610021, + 0x1020000d, + 0x23c484f2, + 0x00030880, + 0x00240821, + 0x8c210000, + 0x00000027, + 0x14250004, + 0x00000027, + 0x00030880, + 0x00240821, + 0xac200000, + 0x28610020, + 0x1420fff5, + 0x24630001, + 0x03e00008, + 0x23bd0008, + 0x23bdfff8, + 0xafbf0000, + 0x8fa1000c, + 0x00000027, + 0x14200003, + 0x00000027, + 0x0c0006b4, + 0xafa00004, + 0x23c28052, + 0x0c0006b4, + 0xafa20004, + 0x8fa20000, + 0x00000027, + 0x00400008, + 0x23bd0008, + 0x23bdfff0, + 0xafbf0000, + 0x23c584f2, + 0x20030020, + 0x04600010, + 0x00000027, + 0x00031080, + 0x00451021, + 0x8c440000, + 0x00000027, + 0x10800008, + 0x00000027, + 0xafa3000c, + 0x00030880, + 0x00250821, + 0x0080f809, + 0xac200000, + 0x8fa3000c, + 0x23c584f2, + 0x080006b8, + 0x2463ffff, + 0x8fa20014, + 0x0c001328, + 0xafa20004, + 0x8fa20000, + 0x00000027, + 0x00400008, + 0x23bd0010, + 0x23bdefe4, + 0xafbf0000, + 0x23a4001c, + 0xafa40004, + 0x24831000, + 0xafa30008, + 0x8fa21020, + 0x23a31020, + 0xafa2000c, + 0x24630004, + 0x0c00076b, + 0xafa30010, + 0x23a5001c, + 0x00012025, + 0x20010001, + 0xafa10004, + 0xafa50008, + 0x00850823, + 0x0c001355, + 0xafa1000c, + 0xafa10014, + 0x0421000c, + 0x00012025, + 0x8fc28032, + 0x00000027, + 0x24420001, + 0x2841000a, + 0x14200006, + 0xafc28032, + 0x20010001, + 0x0c0006a5, + 0xafa10004, + 0x8fa40014, + 0x00000027, + 0x8fa20000, + 0x23bd101c, + 0x00400008, + 0x00040825, + 0x23bdefe4, + 0xafbf0000, + 0x23a4001c, + 0xafa40004, + 0x24831000, + 0xafa30008, + 0x8fa11024, + 0x23a31024, + 0xafa1000c, + 0x24630004, + 0x0c00076b, + 0xafa30010, + 0x8fa21020, + 0x23a5001c, + 0xafa20004, + 0xafa50008, + 0x00251023, + 0x0c001355, + 0xafa2000c, + 0xafa10014, + 0x0421000c, + 0x00012025, + 0x8fc18032, + 0x00000027, + 0x24210001, + 0x2822000a, + 0x14400006, + 0xafc18032, + 0x20020001, + 0x0c0006a5, + 0xafa20004, + 0x8fa40014, + 0x00000027, + 0x8fa20000, + 0x23bd101c, + 0x00400008, + 0x00040825, + 0x23bdffe4, + 0xafbf0000, + 0x8fa40020, + 0x8fc28036, + 0x24831000, + 0xafa20014, + 0xafa40004, + 0xafa30008, + 0x8fa20024, + 0x23a30024, + 0xafa2000c, + 0x24630004, + 0x0c00076b, + 0xafa30010, + 0x8fa20014, + 0x00000027, + 0xafc28036, + 0x8fa20020, + 0x00000027, + 0x00220823, + 0x8fa20000, + 0x00000027, + 0x00400008, + 0x23bd001c, + 0x23bdfffc, + 0x8fc680a2, + 0x23c48146, + 0x83a1000b, + 0x00000027, + 0x3021007f, + 0x00012e00, + 0x00052e03, + 0x00051600, + 0x00021603, + 0x00441021, + 0x80420000, + 0x00000027, + 0x1440000d, + 0x00000027, + 0x28c2001e, + 0x14400004, + 0x00000027, + 0x23bd0004, + 0x03e00008, + 0x20010001, + 0x00051600, + 0x00021603, + 0x00441021, + 0x24c10001, + 0xafc180a2, + 0xa0460000, + 0x00050e00, + 0x00010e03, + 0x00240821, + 0x80210000, + 0x23c280ce, + 0x00010880, + 0x8fa3000c, + 0x00220821, + 0xac230000, + 0x23bd0004, + 0x03e00008, + 0x00000825, + 0x23bdffec, + 0xafbf0000, + 0x8fa40018, + 0x00000027, + 0xafa40004, + 0x24830400, + 0xafa30008, + 0x8fa2001c, + 0x00000027, + 0xafa2000c, + 0x8fa30020, + 0x0c00076b, + 0xafa30010, + 0x8fa20000, + 0x00000027, + 0x00400008, + 0x23bd0014, + 0x23bdffd0, + 0xafbf0000, + 0x8fa5003c, + 0x8fc1802e, + 0x00000027, + 0xafa10018, + 0x8fc28002, + 0x00000027, + 0xafa20014, + 0x8fa80034, + 0x00000027, + 0xafc8802e, + 0x8fa20038, + 0x00000027, + 0x2442ffff, + 0xafc28002, + 0x00052025, + 0x80840000, + 0x20010025, + 0x1081002a, + 0x24a50001, + 0x1480000c, + 0x00000027, + 0xa1000000, + 0x8fa10018, + 0x00000027, + 0xafc1802e, + 0x8fa20014, + 0x00000027, + 0xafc28002, + 0x8fa20000, + 0x23bd0030, + 0x00400008, + 0x00080825, + 0x8fc18002, + 0x00000027, + 0x0101182b, + 0x10600005, + 0x00000027, + 0x00081025, + 0x25080001, + 0xafc8802e, + 0xa0440000, + 0x8fc18036, + 0x00000027, + 0x24210001, + 0xafc18036, + 0x2001000a, + 0x14810003, + 0x00000027, + 0x0800077b, + 0xafc08036, + 0x20010009, + 0x1481ffda, + 0x00000027, + 0x8fc28036, + 0x00000027, + 0x24420007, + 0x201cfff8, + 0x005c1024, + 0x0800077b, + 0xafc28036, + 0x00004825, + 0x00052025, + 0x24a50001, + 0xafa5003c, + 0x80840000, + 0x2006ffff, + 0x00004025, + 0x2002002d, + 0x14820006, + 0x00003825, + 0x00052025, + 0x24a50001, + 0xafa5003c, + 0x80840000, + 0x20080001, + 0x28820030, + 0x14400005, + 0x00000027, + 0x20010039, + 0x0024182a, + 0x1060004c, + 0x00000027, + 0x11000002, + 0x00000027, + 0x00073823, + 0x2001002e, + 0x1081002b, + 0x00000027, + 0x14800003, + 0x00000027, + 0x24a2ffff, + 0xafa2003c, + 0x8fa20040, + 0x23c18146, + 0xafa20004, + 0xafa7002c, + 0xafa70008, + 0xafa60028, + 0xafa6000c, + 0xafa90024, + 0xafa90010, + 0x3082007f, + 0x00220821, + 0x80210000, + 0x23c280ce, + 0x00010880, + 0x00220821, + 0x8c210000, + 0x00000027, + 0x0020f809, + 0x00000027, + 0x8fc8802e, + 0x8fa7002c, + 0x8fa60028, + 0x8fa5003c, + 0x04210009, + 0x00012025, + 0x8fa30024, + 0x00040823, + 0x00052025, + 0x24a50001, + 0xafa5003c, + 0x80840000, + 0x080007c5, + 0x00614825, + 0x8fa10040, + 0x00000027, + 0x00240821, + 0x0800077b, + 0xafa10040, + 0x00052025, + 0x24a50001, + 0xafa5003c, + 0x80840000, + 0x00000027, + 0x28820030, + 0x1440ffcf, + 0x00000027, + 0x20010039, + 0x0024182a, + 0x10600003, + 0x00000027, + 0x080007c5, + 0x00000027, + 0x04c10002, + 0x00000027, + 0x00003025, + 0x2002000a, + 0x00c20018, + 0x00000812, + 0x00240821, + 0x00052025, + 0x24a50001, + 0xafa5003c, + 0x80840000, + 0x080007f4, + 0x2426ffd0, + 0x2001000a, + 0x00e10018, + 0x00001012, + 0x00441021, + 0x00052025, + 0x24a50001, + 0xafa5003c, + 0x80840000, + 0x080007b8, + 0x2447ffd0, + 0x23bdffb4, + 0xafbf0000, + 0x8fa6005c, + 0x8fa40050, + 0x8fa80060, + 0x8fa70058, + 0x00005025, + 0x30c2000f, + 0x2441fffb, + 0x1c20005b, + 0x23a9002c, + 0x10200055, + 0x00000027, + 0x38410001, + 0x1020004e, + 0x00000027, + 0x38410002, + 0x10200041, + 0x00000027, + 0x38410004, + 0x1020003a, + 0x00000027, + 0x8c850000, + 0x20010004, + 0xafa1001c, + 0x30c20004, + 0x14400003, + 0x00000027, + 0x04a0002f, + 0x00000027, + 0xa3a00049, + 0x2004001c, + 0x00a8001b, + 0x00001010, + 0x24460030, + 0x20010039, + 0x0026182a, + 0x10600002, + 0x00000027, + 0x24c60027, + 0x01240821, + 0x28820002, + 0x10400013, + 0xa0260000, + 0x11400005, + 0x00000027, + 0x2484ffff, + 0x01240821, + 0x2003002d, + 0xa0230000, + 0x01240821, + 0xafa10004, + 0x8fa20054, + 0x2001ffff, + 0xafa20008, + 0x0c0008af, + 0xafa1000c, + 0x8fa1001c, + 0x8fa20000, + 0x00000027, + 0x00400008, + 0x23bd004c, + 0x00a8001b, + 0x04e00006, + 0x00002812, + 0x2002001e, + 0x00471023, + 0x0082082a, + 0x10200005, + 0x00000027, + 0x1ca00003, + 0x00000027, + 0x08000840, + 0x00000027, + 0x08000834, + 0x2484ffff, + 0x200a0001, + 0x08000832, + 0x00052823, + 0x8c850000, + 0x20010004, + 0x0800082d, + 0xafa1001c, + 0x8c820000, + 0x00000027, + 0x00022400, + 0x00042403, + 0x00040c00, + 0x00010c03, + 0x20020004, + 0xafa2001c, + 0x0800082d, + 0x00012825, + 0x8c850000, + 0x20010004, + 0x0800082d, + 0xafa1001c, + 0x8c850000, + 0x20010004, + 0x0800082d, + 0xafa1001c, + 0x38410006, + 0x1020002b, + 0x00000027, + 0x38410009, + 0x10200003, + 0x00000027, + 0x0800082a, + 0x00000027, + 0x8c850000, + 0x20010004, + 0x04a10003, + 0xafa1001c, + 0x00052823, + 0x200a0001, + 0xa3a00049, + 0x2004001c, + 0x00a8001a, + 0x00000810, + 0x24260030, + 0x20020039, + 0x0046182a, + 0x10600002, + 0x00000027, + 0x24c60027, + 0x01241021, + 0xa0460000, + 0x28820002, + 0x10400003, + 0x00000027, + 0x08000840, + 0x00000027, + 0x00a8001a, + 0x04e00006, + 0x00002812, + 0x2002001e, + 0x00471023, + 0x0082082a, + 0x10200005, + 0x00000027, + 0x1ca00003, + 0x00000027, + 0x08000840, + 0x00000027, + 0x08000889, + 0x2484ffff, + 0x8c810000, + 0x00000027, + 0x00012400, + 0x00042403, + 0x3082ffff, + 0x20010004, + 0xafa1001c, + 0x0800082d, + 0x00022825, + 0x23bdfff0, + 0x8faa0014, + 0x8fab0018, + 0x8fa9001c, + 0x8fc88002, + 0x8fc78036, + 0x8fc5802e, + 0x000a3025, + 0x00060825, + 0x80210000, + 0x24c60001, + 0x10200006, + 0x00002025, + 0x00060825, + 0x80210000, + 0x24c60001, + 0x1420fffc, + 0x24840001, + 0x05600011, + 0x00000027, + 0x008b182a, + 0x1060000e, + 0x00000027, + 0x00a8182b, + 0x10600006, + 0x00000027, + 0x00051025, + 0x24a50001, + 0xafc5802e, + 0x20030020, + 0xa0430000, + 0x24e70001, + 0x24840001, + 0x008b182a, + 0x1460fff4, + 0xafc78036, + 0x000a3025, + 0x80c60000, + 0x00000027, + 0x10c00015, + 0x254a0001, + 0x1120fffa, + 0x00000027, + 0x00a8182b, + 0x10600005, + 0x00000027, + 0x00051025, + 0x24a50001, + 0xafc5802e, + 0xa0460000, + 0x24e70001, + 0x2001000a, + 0x14c1001d, + 0xafc78036, + 0x00003825, + 0xafc08036, + 0x000a3025, + 0x80c60000, + 0x254a0001, + 0x14c0ffed, + 0x2529ffff, + 0x05610012, + 0x00000027, + 0x000b3023, + 0x0086182a, + 0x1060000e, + 0x00000027, + 0x00a8182b, + 0x10600006, + 0x00000027, + 0x00051025, + 0x24a50001, + 0xafc5802e, + 0x20030020, + 0xa0430000, + 0x24e70001, + 0x24840001, + 0x0086182a, + 0x1460fff4, + 0xafc78036, + 0x03e00008, + 0x23bd0010, + 0x20010009, + 0x14c1ffe4, + 0x00000027, + 0x24e20007, + 0x201cfff8, + 0x005c3824, + 0x080008e7, + 0xafc78036, + 0x23bdfff0, + 0xafbf0000, + 0x23c1803a, + 0xafa10004, + 0xafa00008, + 0x2002ffff, + 0x0c0008af, + 0xafa2000c, + 0x8fa20000, + 0x23bd0010, + 0x00400008, + 0x00000825, + 0x23bdffec, + 0xafbf0000, + 0x8fa10018, + 0x23a20010, + 0x8c210000, + 0x00000027, + 0xa3a10010, + 0xa3a00011, + 0xafa20004, + 0x8fa1001c, + 0x2002ffff, + 0xafa10008, + 0x0c0008af, + 0xafa2000c, + 0x8fa20000, + 0x23bd0014, + 0x00400008, + 0x20010004, + 0x23bdffe8, + 0xafbf0000, + 0x8fa3001c, + 0x00000027, + 0xafa30004, + 0x8fa20020, + 0x00000027, + 0xafa20008, + 0x8fa30024, + 0x00000027, + 0xafa3000c, + 0x8fa20028, + 0x2003000a, + 0xafa20010, + 0x0c000814, + 0xafa30014, + 0x8fa20000, + 0x00000027, + 0x00400008, + 0x23bd0018, + 0x23bdfffc, + 0x23bd0004, + 0x03e00008, + 0x2001fffe, + 0x23bdfffc, + 0x8fa10014, + 0x00000027, + 0x30210001, + 0x10200004, + 0x00000027, + 0x23bd0004, + 0x03e00008, + 0x2001fff8, + 0x23bd0004, + 0x03e00008, + 0x2001ffff, + 0x23bdffe8, + 0xafbf0000, + 0x8fa2001c, + 0x00000027, + 0xafa20004, + 0x8fa30020, + 0x00000027, + 0xafa30008, + 0x8fa20024, + 0x00000027, + 0xafa2000c, + 0x8fa30028, + 0x20020008, + 0xafa30010, + 0x0c000814, + 0xafa20014, + 0x8fa20000, + 0x00000027, + 0x00400008, + 0x23bd0018, + 0x23bdfff0, + 0xafbf0000, + 0x8fa10014, + 0x00000027, + 0x8c210000, + 0x00000027, + 0xafa10004, + 0x8fa20018, + 0x00000027, + 0xafa20008, + 0x8fa1001c, + 0x0c0008af, + 0xafa1000c, + 0x8fa20000, + 0x23bd0010, + 0x00400008, + 0x20010004, + 0x23bdfffc, + 0x23bd0004, + 0x03e00008, + 0x2001fffc, + 0x23bdffe8, + 0xafbf0000, + 0x8fa2001c, + 0x00000027, + 0xafa20004, + 0x8fa30020, + 0x00000027, + 0xafa30008, + 0x8fa20024, + 0x00000027, + 0xafa2000c, + 0x8fa30028, + 0x20020010, + 0xafa30010, + 0x0c000814, + 0xafa20014, + 0x8fa20000, + 0x00000027, + 0x00400008, + 0x23bd0018, + 0x23bdfffc, + 0x8fc4802e, + 0x8fc28002, + 0x00000027, + 0x0082182b, + 0x10600005, + 0x00000027, + 0x24820001, + 0xafc2802e, + 0x20030025, + 0xa0830000, + 0x23bd0004, + 0x03e00008, + 0x00000825, + 0x23bdff70, + 0xafbf0000, + 0x8fad00a8, + 0x8fa900a0, + 0x23a80040, + 0xafa0001c, + 0xc7a10094, + 0xc7a00098, + 0x00000027, + 0x4620c03e, + 0x00000027, + 0x4501000b, + 0x23ac0068, + 0xc7a30094, + 0xc7a20098, + 0x00000027, + 0x4622c001, + 0xe7a10094, + 0xe7a00098, + 0x8fa1001c, + 0x00000027, + 0x24210001, + 0xafa1001c, + 0xafa0002c, + 0xc7a10094, + 0xc7a00098, + 0x00000027, + 0x4620c032, + 0x00000027, + 0x4501005d, + 0x4620c106, + 0xc7a10094, + 0xc7a00098, + 0x23a1002c, + 0xe7a10004, + 0xe7a00008, + 0x0c000b9b, + 0xafa1000c, + 0xc7c1804a, + 0xc7c0804e, + 0xc7a2002c, + 0x00000027, + 0x468010a1, + 0x46201002, + 0x46200024, + 0xe7a0002c, + 0x8fa1002c, + 0x00000027, + 0x00012843, + 0xafa50028, + 0x00050823, + 0x0c000b71, + 0xafa10004, + 0xc7a30094, + 0xc7a20098, + 0x00000027, + 0x46201002, + 0xe7a10030, + 0xe7a00034, + 0x8fa10028, + 0x8fa2002c, + 0x00000027, + 0x00220823, + 0x0c000b71, + 0xafa10004, + 0x8fad00a8, + 0x23ac0068, + 0x8fa900a0, + 0x23a80040, + 0x46200086, + 0xc7a10030, + 0xc7a00034, + 0x00000027, + 0x46220102, + 0x4624e03e, + 0x00000027, + 0x45010014, + 0x00000027, + 0x8fa1002c, + 0x00000027, + 0x2421ffff, + 0xafa1002c, + 0x8fa10028, + 0x8fa2002c, + 0x00000027, + 0x00220823, + 0x0c000b71, + 0xafa10004, + 0x8fad00a8, + 0x8fa900a0, + 0x23a80040, + 0xc7a30030, + 0xc7a20034, + 0x00000027, + 0x46201102, + 0x080009e0, + 0x23ac0068, + 0xc7c18042, + 0xc7c08046, + 0x00000027, + 0x4624003e, + 0x00000027, + 0x45000014, + 0x00000027, + 0x8fa1002c, + 0x00000027, + 0x24210001, + 0xafa1002c, + 0x8fa10028, + 0x8fa2002c, + 0x00000027, + 0x00220823, + 0x0c000b71, + 0xafa10004, + 0x8fad00a8, + 0x8fa900a0, + 0x23a80040, + 0xc7a30030, + 0xc7a20034, + 0x00000027, + 0x46201102, + 0x080009f7, + 0x23ac0068, + 0x05210002, + 0x00000027, + 0x20090008, + 0x20020067, + 0x15a20003, + 0x00000027, + 0x1d20010f, + 0x00000027, + 0x2002001e, + 0x0049182a, + 0x10600002, + 0x00000027, + 0x2009001e, + 0x25250002, + 0x20020066, + 0x15a20008, + 0xafa900a0, + 0x8fa1002c, + 0x00000027, + 0x00a12821, + 0x1ca00003, + 0x00000027, + 0x20050001, + 0x4620c106, + 0x28a20020, + 0x14400009, + 0x00000027, + 0x20010065, + 0x15a10003, + 0x00000027, + 0x2009ffff, + 0xafa900a0, + 0x200d0065, + 0x080009ad, + 0xafad00a8, + 0x00003825, + 0x00e5182a, + 0x10600018, + 0x00000027, + 0x46202024, + 0x44060000, + 0x00000027, + 0x44860000, + 0x00000027, + 0x46800021, + 0x4620203c, + 0x00000027, + 0x45000002, + 0x00000027, + 0x24c6ffff, + 0x44860000, + 0x00ec0821, + 0x46800021, + 0x46202101, + 0x24c30030, + 0xa0230001, + 0xc7c18042, + 0xc7c08046, + 0x24e70001, + 0x00e5182a, + 0x1460ffea, + 0x46202102, + 0x20060005, + 0x24a5ffff, + 0x04a00013, + 0x00000027, + 0x00ac0821, + 0x80220001, + 0x00000027, + 0x00461821, + 0xa0230001, + 0x00ac0821, + 0x80210001, + 0x20020039, + 0x0041182a, + 0x10600006, + 0x00003025, + 0x00ac0821, + 0x80230001, + 0x24c60001, + 0x2463fff6, + 0xa0230001, + 0x08000a51, + 0x24a5ffff, + 0x10c00007, + 0x200a0001, + 0x20020031, + 0xa3a20068, + 0x8fa1002c, + 0x00005025, + 0x24210001, + 0xafa1002c, + 0x8fa2001c, + 0x00000027, + 0x10400006, + 0x00002825, + 0x00051025, + 0x24a50001, + 0x01020821, + 0x2002002d, + 0xa0220000, + 0x25270001, + 0x00095825, + 0x20020067, + 0x15a2000b, + 0x00003025, + 0x8fa1002c, + 0x00000027, + 0x2822fffb, + 0x14400006, + 0x00000027, + 0x8fa2002c, + 0x00000027, + 0x0122182a, + 0x10600099, + 0x00000027, + 0x20010066, + 0x15a10011, + 0x00000027, + 0x8fa1002c, + 0x00000027, + 0x00013023, + 0x04c10002, + 0x00000027, + 0x00003025, + 0x0126182a, + 0x10600002, + 0x00000027, + 0x00073025, + 0x8fa1002c, + 0x00000027, + 0x00e13821, + 0x04e10002, + 0x00000027, + 0x00003825, + 0x18c00010, + 0x00000027, + 0x00c71021, + 0x144b0006, + 0x00000027, + 0x00051025, + 0x24a50001, + 0x01020821, + 0x2002002e, + 0xa0220000, + 0x00051025, + 0x01020821, + 0x20020030, + 0xa0220000, + 0x24c6ffff, + 0x08000a98, + 0x24a50001, + 0x18e00013, + 0x00000027, + 0x00c70821, + 0x142b0006, + 0x00000027, + 0x00051025, + 0x24a50001, + 0x01020821, + 0x2002002e, + 0xa0220000, + 0x00051025, + 0x01020821, + 0x000a1825, + 0x01831021, + 0x80420000, + 0x254a0001, + 0xa0220000, + 0x24e7ffff, + 0x08000aa9, + 0x24a50001, + 0x20010067, + 0x11a10046, + 0x00000027, + 0x20010068, + 0x11a10043, + 0x00000027, + 0x20010065, + 0x11a10010, + 0x00000027, + 0x20010067, + 0x11a1000d, + 0x00000027, + 0x01051021, + 0xa0400000, + 0xafa80004, + 0x8fa1009c, + 0x2002ffff, + 0xafa10008, + 0x0c0008af, + 0xafa2000c, + 0x8fa20000, + 0x23bd0090, + 0x00400008, + 0x20010008, + 0x24a30001, + 0x01051021, + 0x20010065, + 0xa0410000, + 0x01031021, + 0x2001002b, + 0xa0410000, + 0x8fa6002c, + 0x00000027, + 0x04c10005, + 0x24650001, + 0x00a81021, + 0x2003002d, + 0xa043ffff, + 0x00063023, + 0x28c10064, + 0x1420000e, + 0x00000027, + 0x00051025, + 0x24a50001, + 0x01020821, + 0x20030064, + 0x00c3001a, + 0x00001012, + 0x24420030, + 0xa0220000, + 0x20010064, + 0x00c1001a, + 0x00003010, + 0x00000027, + 0x00000027, + 0x00050825, + 0x24a50001, + 0x01011021, + 0x2003000a, + 0x00c3001a, + 0x00000812, + 0x24210030, + 0xa0410000, + 0x00050825, + 0x01011021, + 0x2003000a, + 0x00c3001a, + 0x00000810, + 0x24210030, + 0xa0410000, + 0x08000ac9, + 0x24a50001, + 0x24a7ffff, + 0x04e00006, + 0x00000027, + 0x01070821, + 0x80210000, + 0x20020030, + 0x1022000f, + 0x00000027, + 0x00073025, + 0x04c0ffb4, + 0x00000027, + 0x01061021, + 0x80420000, + 0x2001002e, + 0x14410005, + 0x00000027, + 0x10c7ffad, + 0x00072825, + 0x08000ac3, + 0x24a50001, + 0x08000b0e, + 0x24c6ffff, + 0x08000b06, + 0x24e7ffff, + 0x8fa1002c, + 0x2002ffff, + 0x00413023, + 0x04c10002, + 0x00000027, + 0x00003025, + 0x8fa1002c, + 0x200d0068, + 0x08000a85, + 0x01215823, + 0x08000a19, + 0x2529ffff, + 0x23bdffe4, + 0xafbf0000, + 0x8fa20020, + 0x00000027, + 0xc4410000, + 0xc4400004, + 0x00000027, + 0xe7a10004, + 0xe7a00008, + 0x8fa20024, + 0x00000027, + 0xafa2000c, + 0x8fa30028, + 0x00000027, + 0xafa30010, + 0x8fa2002c, + 0x20030065, + 0xafa20014, + 0x0c000996, + 0xafa30018, + 0x8fa20000, + 0x00000027, + 0x00400008, + 0x23bd001c, + 0x23bdffe4, + 0xafbf0000, + 0x8fa20020, + 0x00000027, + 0xc4410000, + 0xc4400004, + 0x00000027, + 0xe7a10004, + 0xe7a00008, + 0x8fa20024, + 0x00000027, + 0xafa2000c, + 0x8fa30028, + 0x00000027, + 0xafa30010, + 0x8fa2002c, + 0x20030066, + 0xafa20014, + 0x0c000996, + 0xafa30018, + 0x8fa20000, + 0x00000027, + 0x00400008, + 0x23bd001c, + 0x23bdffe4, + 0xafbf0000, + 0x8fa20020, + 0x00000027, + 0xc4410000, + 0xc4400004, + 0x00000027, + 0xe7a10004, + 0xe7a00008, + 0x8fa20024, + 0x00000027, + 0xafa2000c, + 0x8fa30028, + 0x00000027, + 0xafa30010, + 0x8fa2002c, + 0x20030067, + 0xafa20014, + 0x0c000996, + 0xafa30018, + 0x8fa20000, + 0x00000027, + 0x00400008, + 0x23bd001c, + 0x23bdffec, + 0xafbf0000, + 0x8fa30018, + 0x00000027, + 0x04610008, + 0x00000027, + 0x00030823, + 0x0c000b71, + 0xafa10004, + 0x8fa20000, + 0x23bd0014, + 0x00400008, + 0x4620e003, + 0x2862000a, + 0x1040000b, + 0x00000027, + 0x00031080, + 0x23c18006, + 0x00411021, + 0x8c420000, + 0x00000027, + 0x44820000, + 0x8fa20000, + 0x23bd0014, + 0x00400008, + 0x46800021, + 0x00032043, + 0xafa40010, + 0x00641023, + 0x0c000b71, + 0xafa20004, + 0xe7a10008, + 0xe7a0000c, + 0x8fa10010, + 0x0c000b71, + 0xafa10004, + 0xc7a30008, + 0xc7a2000c, + 0x8fa20000, + 0x23bd0014, + 0x00400008, + 0x46220002, + 0x23bdfff4, + 0x8fa30018, + 0xc7a50010, + 0xc7a40014, + 0x00000027, + 0x4624c032, + 0x00000027, + 0x45000005, + 0x00000027, + 0x4620c006, + 0x23bd000c, + 0x03e00008, + 0xac600000, + 0xe7a50004, + 0xe7a40008, + 0x8fa20004, + 0x00000027, + 0x00021503, + 0x304207ff, + 0x2442fc02, + 0xac620000, + 0x8fa10004, + 0x00000027, + 0x3c1c800f, + 0x379cffff, + 0x003c0824, + 0xafa10004, + 0x8fa20004, + 0x00000027, + 0x3c1c3fe0, + 0x005c1025, + 0xafa20004, + 0xc7a10004, + 0xc7a00008, + 0x03e00008, + 0x23bd000c, + 0x23bdfff0, + 0xafbf0000, + 0xc7a50014, + 0xc7a40018, + 0x00000027, + 0x4624c032, + 0x00000027, + 0x45000005, + 0x00000027, + 0x8fa20000, + 0x23bd0010, + 0x00400008, + 0x4620c006, + 0xe7a50008, + 0xe7a4000c, + 0x8fa10008, + 0x8fa2001c, + 0x00010d03, + 0x302107ff, + 0x00411821, + 0x1c600005, + 0x00000027, + 0x8fa20000, + 0x23bd0010, + 0x00400008, + 0x4620c006, + 0x286207ff, + 0x14400013, + 0x00000027, + 0x4624c03e, + 0x00000027, + 0x45010008, + 0x00000027, + 0x2001ffff, + 0x0c001381, + 0xafa10004, + 0x8fa20000, + 0x00000027, + 0x00400008, + 0x23bd0010, + 0x20020001, + 0x0c001381, + 0xafa20004, + 0x8fa20000, + 0x00000027, + 0x00400008, + 0x23bd0010, + 0x8fa10008, + 0x00031500, + 0x3c1c800f, + 0x379cffff, + 0x003c0824, + 0xafa10008, + 0x8fa10008, + 0x00000027, + 0x00221025, + 0xafa20008, + 0xc7a10008, + 0xc7a0000c, + 0x8fa20000, + 0x00000027, + 0x00400008, + 0x23bd0010, + 0x23bdfff0, + 0x8fa5001c, + 0xc7a50014, + 0xc7a40018, + 0x00000027, + 0x4624e03e, + 0x00000027, + 0x45010006, + 0x00000027, + 0xe4b90000, + 0xe4b80004, + 0x23bd0010, + 0x03e00008, + 0x46202006, + 0xe7a50008, + 0xe7a4000c, + 0x8fa10008, + 0x00000027, + 0x00010d03, + 0x302107ff, + 0x2424fc02, + 0x20010015, + 0x0024182a, + 0x14600013, + 0x00000027, + 0x8fc280c6, + 0x8fa30008, + 0x00821007, + 0x201cffff, + 0x005c1026, + 0x00621024, + 0xafa20008, + 0xafa0000c, + 0xc7a10008, + 0xc7a0000c, + 0x00000027, + 0xe4a10000, + 0xe4a00004, + 0xc7a30008, + 0xc7a2000c, + 0x23bd0010, + 0x03e00008, + 0x46222001, + 0x20020035, + 0x0044182a, + 0x1460fff3, + 0x00000027, + 0x8fc280ca, + 0x2481ffea, + 0x00220807, + 0x201cffff, + 0x003c0826, + 0x8fa3000c, + 0x00000027, + 0x00610824, + 0x08000c1f, + 0xafa1000c, + 0x23bdfffc, + 0x8fa30008, + 0x8fa2000c, + 0x00000027, + 0x80410000, + 0x80640000, + 0x1020000c, + 0x00000027, + 0x24630001, + 0x1024fffa, + 0x24420001, + 0x0024082b, + 0x14200004, + 0x00000027, + 0x23bd0004, + 0x03e00008, + 0x2001ffff, + 0x03e00008, + 0x23bd0004, + 0x23bd0004, + 0x03e00008, + 0x0024082b, + 0x23bdfffc, + 0x8fa20008, + 0x8fa1000c, + 0x00000027, + 0x80230000, + 0x00000027, + 0xa0430000, + 0x24420001, + 0x1460fffb, + 0x24210001, + 0x8fa10008, + 0x03e00008, + 0x23bd0004, + 0x23bdfffc, + 0x8fa20008, + 0x00000027, + 0x80410000, + 0x00000027, + 0x10200007, + 0x24420001, + 0x00020825, + 0x80230000, + 0x00000027, + 0x1460fffd, + 0x24210001, + 0x00220823, + 0x03e00008, + 0x23bd0004, + 0x23bdfff4, + 0xafbf0000, + 0x8fa20010, + 0x23a30010, + 0xafa20004, + 0x24630004, + 0x0c001341, + 0xafa30008, + 0x8fa20000, + 0x00000027, + 0x00400008, + 0x23bd000c, + 0x23bdffec, + 0xafbf0000, + 0x8fa40018, + 0x2006001c, + 0x8fa2001c, + 0x90830000, + 0x24450001, + 0xa0430000, + 0x80810000, + 0x00000027, + 0x2422ffe9, + 0x1c4001c9, + 0x20070040, + 0x104001ab, + 0x00000027, + 0x2422fff2, + 0x1c4000c7, + 0x00000027, + 0x104000ae, + 0x00000027, + 0x2422fff6, + 0x1c400052, + 0x00000027, + 0x10400030, + 0x00000027, + 0x00201026, + 0x1040001b, + 0x00000027, + 0x38220001, + 0x10400018, + 0x00000027, + 0x38220002, + 0x1040001c, + 0x00000027, + 0x38220003, + 0x1040000a, + 0x00000027, + 0x23c180a6, + 0xafa10004, + 0x80820000, + 0x0c0006d0, + 0xafa20008, + 0x8fa20000, + 0x23bd0014, + 0x00400008, + 0x00000825, + 0x84820004, + 0x00000027, + 0xa0a20000, + 0x84820004, + 0x00000027, + 0x00021203, + 0xa0a20001, + 0x24a50002, + 0x8fa2001c, + 0x00000027, + 0x00a20823, + 0x8fa20000, + 0x00000027, + 0x00400008, + 0x23bd0014, + 0x00050825, + 0x9083000c, + 0x24a50001, + 0xa0230000, + 0x8fa2001c, + 0x00000027, + 0x00a20823, + 0x8fa20000, + 0x00000027, + 0x00400008, + 0x23bd0014, + 0x84820002, + 0x24a10002, + 0xa0a20000, + 0x84820002, + 0x00000027, + 0x00021203, + 0xa0a20001, + 0xafa10010, + 0xafa10004, + 0x24810008, + 0xafa10008, + 0x0c0012b8, + 0xafa6000c, + 0x8fa10010, + 0x2002001c, + 0x2421001c, + 0xafa10010, + 0xafa10004, + 0x8fa10018, + 0x00000027, + 0x24210024, + 0xafa10008, + 0x0c0012b8, + 0xafa2000c, + 0x8fa10010, + 0x8fa2001c, + 0x2425001c, + 0x00a20823, + 0x8fa20000, + 0x00000027, + 0x00400008, + 0x23bd0014, + 0x3822000b, + 0x10400033, + 0x00000027, + 0x3822000c, + 0x1040001b, + 0x00000027, + 0x3822000d, + 0x10400003, + 0x00000027, + 0x08000c9a, + 0x00000027, + 0x84810002, + 0x00000027, + 0xa0a10000, + 0x84810002, + 0x00000027, + 0x00010a03, + 0xa0a10001, + 0x84820004, + 0x24a50002, + 0xa0a20000, + 0x84820004, + 0x00000027, + 0x00021203, + 0xa0a20001, + 0x8fa2001c, + 0x24a50002, + 0x00a20823, + 0x8fa20000, + 0x00000027, + 0x00400008, + 0x23bd0014, + 0x84810002, + 0x00000027, + 0xa0a10000, + 0x84810002, + 0x00000027, + 0x00010a03, + 0xa0a10001, + 0x8482000a, + 0x24a50002, + 0xa0a20000, + 0x8482000a, + 0x00000027, + 0x00021203, + 0xa0a20001, + 0x8fa2001c, + 0x24a50002, + 0x00a20823, + 0x8fa20000, + 0x00000027, + 0x00400008, + 0x23bd0014, + 0x84810002, + 0x00000027, + 0xa0a10000, + 0x84810002, + 0x00000027, + 0x00010a03, + 0xa0a10001, + 0x84820004, + 0x24a50002, + 0xa0a20000, + 0x84820004, + 0x00000027, + 0x00021203, + 0xa0a20001, + 0x8c810010, + 0x24a50002, + 0xa0a10000, + 0x8c810010, + 0x00000027, + 0x00010a02, + 0xa0a10001, + 0x8c810010, + 0x00000027, + 0x00010c02, + 0xa0a10002, + 0x8c810010, + 0x00000027, + 0x00010e02, + 0xa0a10003, + 0x8fa2001c, + 0x24a50004, + 0x00a20823, + 0x8fa20000, + 0x00000027, + 0x00400008, + 0x23bd0014, + 0x84810002, + 0x24a20002, + 0xa0a10000, + 0x84810002, + 0x00000027, + 0x00010a03, + 0xa0a10001, + 0xafa20010, + 0xafa20004, + 0x2482000c, + 0xafa20008, + 0x0c0012b8, + 0xafa6000c, + 0x8fa20010, + 0x00000027, + 0x2445001c, + 0x8fa2001c, + 0x00000027, + 0x00a20823, + 0x8fa20000, + 0x00000027, + 0x00400008, + 0x23bd0014, + 0x2422ffed, + 0x1c40004e, + 0x00000027, + 0x1040ffc1, + 0x00000027, + 0x3822000f, + 0x1040ffbe, + 0x00000027, + 0x38220010, + 0x10400034, + 0x00000027, + 0x38220011, + 0x1040ffb8, + 0x00000027, + 0x38220012, + 0x10400003, + 0x00000027, + 0x08000c9a, + 0x00000027, + 0x84820002, + 0x24a10002, + 0xa0a20000, + 0x84820002, + 0x00000027, + 0x00021203, + 0xa0a20001, + 0xafa10010, + 0xafa10004, + 0x2481000c, + 0xafa10008, + 0x0c0012b8, + 0xafa6000c, + 0x8fa60018, + 0x8fa10010, + 0x00000027, + 0x2424001c, + 0x8cc10008, + 0x00000027, + 0xa0810000, + 0x8cc10008, + 0x00000027, + 0x00010a03, + 0xa0810001, + 0x8cc10008, + 0x00000027, + 0x00010c03, + 0xa0810002, + 0x8cc10008, + 0x00000027, + 0x00010e03, + 0xa0810003, + 0x24810004, + 0x90c30028, + 0x24250001, + 0xa0230000, + 0x8fa2001c, + 0x00000027, + 0x00a20823, + 0x8fa20000, + 0x00000027, + 0x00400008, + 0x23bd0014, + 0x84820002, + 0x00000027, + 0xa0a20000, + 0x84820002, + 0x00000027, + 0x00021203, + 0xa0a20001, + 0x24a20002, + 0x90830028, + 0x24450001, + 0xa0430000, + 0x8fa2001c, + 0x00000027, + 0x00a20823, + 0x8fa20000, + 0x00000027, + 0x00400008, + 0x23bd0014, + 0x38220014, + 0x10400067, + 0x00000027, + 0x38220015, + 0x1040003b, + 0x00000027, + 0x38220016, + 0x10400003, + 0x00000027, + 0x08000c9a, + 0x00000027, + 0x84810002, + 0x00000027, + 0xa0a10000, + 0x84810002, + 0x00000027, + 0x00010a03, + 0xa0a10001, + 0x8c820008, + 0x24a50002, + 0xa0a20000, + 0x8c820008, + 0x00000027, + 0x00021203, + 0xa0a20001, + 0x8c820008, + 0x00000027, + 0x00021403, + 0xa0a20002, + 0x8c820008, + 0x00000027, + 0x00021603, + 0xa0a20003, + 0xa0a00004, + 0xa0a00005, + 0xa0a00006, + 0xa0a00007, + 0x8c81000c, + 0x24a50008, + 0xa0a10000, + 0x8c81000c, + 0x24a20002, + 0x00010a03, + 0xa0a10001, + 0xafa20010, + 0xafa20004, + 0x8c820010, + 0x00000027, + 0xafa20008, + 0x8c81000c, + 0x0c0012b8, + 0xafa1000c, + 0x8fa20018, + 0x8fa10010, + 0x8c42000c, + 0x00000027, + 0x00222821, + 0x8fa2001c, + 0x00000027, + 0x00a20823, + 0x8fa20000, + 0x00000027, + 0x00400008, + 0x23bd0014, + 0x84820002, + 0x00000027, + 0xa0a20000, + 0x84820002, + 0x00000027, + 0x00021203, + 0xa0a20001, + 0x84810004, + 0x24a50002, + 0xa0a10000, + 0x84810004, + 0x00000027, + 0x00010a03, + 0xa0a10001, + 0x8c82000c, + 0x24a50002, + 0xa0a20000, + 0x8c82000c, + 0x24a10002, + 0x00021203, + 0xa0a20001, + 0xafa10010, + 0xafa10004, + 0x8c810010, + 0x00000027, + 0xafa10008, + 0x8c82000c, + 0x0c0012b8, + 0xafa2000c, + 0x8fa10018, + 0x8fa20010, + 0x8c21000c, + 0x00000027, + 0x00412821, + 0x8fa2001c, + 0x00000027, + 0x00a20823, + 0x8fa20000, + 0x00000027, + 0x00400008, + 0x23bd0014, + 0x84820002, + 0x00000027, + 0xa0a20000, + 0x84820002, + 0x00000027, + 0x00021203, + 0xa0a20001, + 0x8c810008, + 0x24a50002, + 0xa0a10000, + 0x8c810008, + 0x00000027, + 0x00010a03, + 0xa0a10001, + 0x8c810008, + 0x00000027, + 0x00010c03, + 0xa0a10002, + 0x8c810008, + 0x00000027, + 0x00010e03, + 0xa0a10003, + 0xa0a00004, + 0xa0a00005, + 0xa0a00006, + 0xa0a00007, + 0x8c82000c, + 0x24a50008, + 0xa0a20000, + 0x8c82000c, + 0x00000027, + 0x00021203, + 0xa0a20001, + 0x8fa2001c, + 0x24a50002, + 0x00a20823, + 0x8fa20000, + 0x00000027, + 0x00400008, + 0x23bd0014, + 0x84810002, + 0x00000027, + 0xa0a10000, + 0x84810002, + 0x00000027, + 0x00010a03, + 0xa0a10001, + 0x84820004, + 0x24a50002, + 0xa0a20000, + 0x84820004, + 0x00000027, + 0x00021203, + 0xa0a20001, + 0x8c81000c, + 0x24a50002, + 0xa0a10000, + 0x8c81000c, + 0x00000027, + 0x00010a03, + 0xa0a10001, + 0x8fa2001c, + 0x24a50002, + 0x00a20823, + 0x8fa20000, + 0x00000027, + 0x00400008, + 0x23bd0014, + 0x2422ffe0, + 0x1c400079, + 0x00000027, + 0x10400062, + 0x00000027, + 0x2422ffe4, + 0x1c40001f, + 0x00000027, + 0x1040000f, + 0x00000027, + 0x38220018, + 0x1040000c, + 0x00000027, + 0x38220019, + 0x1040fe8f, + 0x00000027, + 0x3822001a, + 0x1040feda, + 0x00000027, + 0x3822001b, + 0x1040fe89, + 0x00000027, + 0x08000c9a, + 0x00000027, + 0x84820002, + 0x00000027, + 0xa0a20000, + 0x84820002, + 0x00000027, + 0x00021203, + 0xa0a20001, + 0x8fa2001c, + 0x24a50002, + 0x00a20823, + 0x8fa20000, + 0x00000027, + 0x00400008, + 0x23bd0014, + 0x3822001d, + 0x10400020, + 0x00000027, + 0x3822001e, + 0x10400006, + 0x00000027, + 0x3822001f, + 0x1040fe70, + 0x00000027, + 0x08000c9a, + 0x00000027, + 0x84810002, + 0x24a20002, + 0xa0a10000, + 0x84810002, + 0x00000027, + 0x00010a03, + 0xa0a10001, + 0xafa20010, + 0xafa20004, + 0x24820008, + 0xafa20008, + 0x0c0012b8, + 0xafa7000c, + 0x8fa20010, + 0x00000027, + 0x24450040, + 0x8fa2001c, + 0x00000027, + 0x00a20823, + 0x8fa20000, + 0x00000027, + 0x00400008, + 0x23bd0014, + 0x84820002, + 0x00000027, + 0xa0a20000, + 0x84820002, + 0x00000027, + 0x00021203, + 0xa0a20001, + 0x84810004, + 0x24a50002, + 0xa0a10000, + 0x84810004, + 0x24a20002, + 0x00010a03, + 0xa0a10001, + 0xafa20010, + 0xafa20004, + 0x24820008, + 0xafa20008, + 0x0c0012b8, + 0xafa7000c, + 0x8fa20010, + 0x00000027, + 0x24450040, + 0x8fa2001c, + 0x00000027, + 0x00a20823, + 0x8fa20000, + 0x00000027, + 0x00400008, + 0x23bd0014, + 0x84820002, + 0x00000027, + 0xa0a20000, + 0x84820002, + 0x00000027, + 0x00021203, + 0xa0a20001, + 0x84810004, + 0x24a50002, + 0xa0a10000, + 0x84810004, + 0x00000027, + 0x00010a03, + 0xa0a10001, + 0x8fa2001c, + 0x24a50002, + 0x00a20823, + 0x8fa20000, + 0x00000027, + 0x00400008, + 0x23bd0014, + 0x2422ffdc, + 0x1c40005f, + 0x00000027, + 0x1040ff3d, + 0x00000027, + 0x38220021, + 0x1040003c, + 0x00000027, + 0x38220022, + 0x10400024, + 0x00000027, + 0x38220023, + 0x10400003, + 0x00000027, + 0x08000c9a, + 0x00000027, + 0x84820002, + 0x00000027, + 0xa0a20000, + 0x84820002, + 0x00000027, + 0x00021203, + 0xa0a20001, + 0x84810004, + 0x24a50002, + 0xa0a10000, + 0x84810004, + 0x24a20002, + 0x00010a03, + 0xa0a10001, + 0xafa20010, + 0xafa20004, + 0x24820008, + 0xafa20008, + 0x0c0012b8, + 0xafa6000c, + 0x8fa20010, + 0x00000027, + 0x2445001c, + 0x8fa2001c, + 0x00000027, + 0x00a20823, + 0x8fa20000, + 0x00000027, + 0x00400008, + 0x23bd0014, + 0x84820002, + 0x00000027, + 0xa0a20000, + 0x84820002, + 0x00000027, + 0x00021203, + 0xa0a20001, + 0x84810008, + 0x24a50002, + 0xa0a10000, + 0x84810008, + 0x00000027, + 0x00010a03, + 0xa0a10001, + 0x8fa2001c, + 0x24a50002, + 0x00a20823, + 0x8fa20000, + 0x00000027, + 0x00400008, + 0x23bd0014, + 0x84820002, + 0x00000027, + 0xa0a20000, + 0x84820002, + 0x00000027, + 0x00021203, + 0xa0a20001, + 0x84810004, + 0x24a50002, + 0xa0a10000, + 0x84810004, + 0x24a20002, + 0x00010a03, + 0xa0a10001, + 0xafa20010, + 0xafa20004, + 0x24820008, + 0xafa20008, + 0x0c0012b8, + 0xafa7000c, + 0x8fa20010, + 0x00000027, + 0x24450040, + 0x8fa2001c, + 0x00000027, + 0x00a20823, + 0x8fa20000, + 0x00000027, + 0x00400008, + 0x23bd0014, + 0x38220025, + 0x1040003f, + 0x00000027, + 0x38220026, + 0x10400006, + 0x00000027, + 0x38220027, + 0x1040ff00, + 0x00000027, + 0x08000c9a, + 0x00000027, + 0x84820002, + 0x00000027, + 0xa0a20000, + 0x84820002, + 0x00000027, + 0x00021203, + 0xa0a20001, + 0x8c810008, + 0x24a50002, + 0xa0a10000, + 0x8c810008, + 0x00000027, + 0x00010a03, + 0xa0a10001, + 0x8c810008, + 0x00000027, + 0x00010c03, + 0xa0a10002, + 0x8c810008, + 0x00000027, + 0x00010e03, + 0xa0a10003, + 0xa0a00004, + 0xa0a00005, + 0xa0a00006, + 0xa0a00007, + 0x8c82000c, + 0x24a50008, + 0xa0a20000, + 0x8c82000c, + 0x24a10002, + 0x00021203, + 0xa0a20001, + 0x24220001, + 0xafa20010, + 0xafa20004, + 0x8c820010, + 0x00000027, + 0xafa20008, + 0x8c81000c, + 0x0c0012b8, + 0xafa1000c, + 0x8fa20018, + 0x8fa10010, + 0x8c42000c, + 0x00000027, + 0x00222821, + 0x8fa2001c, + 0x00000027, + 0x00a20823, + 0x8fa20000, + 0x00000027, + 0x00400008, + 0x23bd0014, + 0x84810002, + 0x00000027, + 0xa0a10000, + 0x84810002, + 0x00000027, + 0x00010a03, + 0xa0a10001, + 0x84820004, + 0x24a50002, + 0xa0a20000, + 0x84820004, + 0x00000027, + 0x00021203, + 0xa0a20001, + 0x8c81000c, + 0x24a50002, + 0xa0a10000, + 0x8c81000c, + 0x24a20002, + 0x00010a03, + 0xa0a10001, + 0x24410001, + 0xafa10010, + 0xafa10004, + 0x8c810010, + 0x00000027, + 0xafa10008, + 0x8c82000c, + 0x0c0012b8, + 0xafa2000c, + 0x8fa10018, + 0x8fa20010, + 0x8c21000c, + 0x00000027, + 0x00412821, + 0x8fa2001c, + 0x00000027, + 0x00a20823, + 0x8fa20000, + 0x00000027, + 0x00400008, + 0x23bd0014, + 0x23bdffec, + 0xafbf0000, + 0x8fa1001c, + 0x2002001c, + 0xafa10010, + 0xafa10004, + 0x8fa10018, + 0x00000027, + 0xafa10008, + 0x0c0012b8, + 0xafa2000c, + 0x8fa30018, + 0x8fa10010, + 0x00000027, + 0x2424001c, + 0x8c61001c, + 0x24820004, + 0xa0810000, + 0x8c61001c, + 0x00000027, + 0x00010a03, + 0xa0810001, + 0x8c61001c, + 0x00000027, + 0x00010c03, + 0xa0810002, + 0x8c61001c, + 0x00000027, + 0x00010e03, + 0xa0810003, + 0x8c610024, + 0x24440004, + 0xa0810000, + 0x8c610024, + 0x00000027, + 0x00010a03, + 0xa0810001, + 0x8c610024, + 0x00000027, + 0x00010c03, + 0xa0810002, + 0x8c610024, + 0x00000027, + 0x00010e03, + 0xa0810003, + 0x8c620028, + 0x24840004, + 0xa0820000, + 0x8c620028, + 0x00000027, + 0x00021203, + 0xa0820001, + 0x8c620028, + 0x00000027, + 0x00021403, + 0xa0820002, + 0x8c620028, + 0x00000027, + 0x00021603, + 0xa0820003, + 0x8c61002c, + 0x24840004, + 0xa0810000, + 0x8c61002c, + 0x00000027, + 0x00010a03, + 0xa0810001, + 0x8c61002c, + 0x00000027, + 0x00010c03, + 0xa0810002, + 0x8c61002c, + 0x00000027, + 0x00010e03, + 0xa0810003, + 0x8c620034, + 0x24840004, + 0xa0820000, + 0x8c620034, + 0x00000027, + 0x00021203, + 0xa0820001, + 0x8c620034, + 0x00000027, + 0x00021403, + 0xa0820002, + 0x8c620034, + 0x00000027, + 0x00021603, + 0xa0820003, + 0xa0800004, + 0xa0800005, + 0xa0800006, + 0xa0800007, + 0x84610038, + 0x24840008, + 0xa0810000, + 0x84610038, + 0x00000027, + 0x00010a03, + 0xa0810001, + 0x8462003a, + 0x24840002, + 0xa0820000, + 0x8462003a, + 0x00000027, + 0x00021203, + 0xa0820001, + 0x84610020, + 0x24840002, + 0xa0810000, + 0x84610020, + 0x00000027, + 0x00010a03, + 0xa0810001, + 0x84620022, + 0x24840002, + 0xa0820000, + 0x84620022, + 0x24810002, + 0x00021203, + 0xa0820001, + 0x8fa2001c, + 0x00000027, + 0x00220823, + 0x8fa20000, + 0x00000027, + 0x00400008, + 0x23bd0014, + 0x23bdffec, + 0xafbf0000, + 0x8fa5001c, + 0x2006001c, + 0x8fa10018, + 0x00000027, + 0x24240001, + 0x80210000, + 0x00000027, + 0xa0a10000, + 0x80a20000, + 0x00000027, + 0x2441ffe9, + 0x1c20014a, + 0x20070040, + 0x10200135, + 0x00000027, + 0x2441fff2, + 0x1c20009e, + 0x00000027, + 0x1020008d, + 0x00000027, + 0x2441fff6, + 0x1c20004c, + 0x00000027, + 0x10200031, + 0x00000027, + 0x00400826, + 0x10200019, + 0x00000027, + 0x38410001, + 0x10200016, + 0x00000027, + 0x38410002, + 0x10200022, + 0x00000027, + 0x38410003, + 0x1020000a, + 0x00000027, + 0x23c280b4, + 0xafa20004, + 0x80a10000, + 0x0c0006d0, + 0xafa10008, + 0x8fa20000, + 0x23bd0014, + 0x00400008, + 0x00000825, + 0x90810000, + 0x90820001, + 0x24840002, + 0x00021200, + 0x00220825, + 0xa4a10004, + 0x8fa20018, + 0x8fa10020, + 0x00000027, + 0x00411021, + 0x14440006, + 0x00000027, + 0x8fa10020, + 0x8fa20000, + 0x00000027, + 0x00400008, + 0x23bd0014, + 0x8fa20000, + 0x23bd0014, + 0x00400008, + 0x00000825, + 0x00040825, + 0x80210000, + 0x00000027, + 0xa0a1000c, + 0x08001048, + 0x24840001, + 0x90820000, + 0x90810001, + 0x24840002, + 0x00010a00, + 0x00411025, + 0xa4a20002, + 0x24a20008, + 0xafa20004, + 0xafa40010, + 0xafa40008, + 0x0c0012b8, + 0xafa6000c, + 0x8fa10010, + 0x8fa2001c, + 0x2424001c, + 0x24420024, + 0xafa20004, + 0xafa40010, + 0xafa40008, + 0x2002001c, + 0x0c0012b8, + 0xafa2000c, + 0x8fa10010, + 0x08001048, + 0x2424001c, + 0x3841000b, + 0x10200023, + 0x00000027, + 0x3841000c, + 0x10200013, + 0x00000027, + 0x3841000d, + 0x10200003, + 0x00000027, + 0x08001039, + 0x00000027, + 0x90810000, + 0x90820001, + 0x24840002, + 0x00021200, + 0x00220825, + 0xa4a10002, + 0x90810000, + 0x90820001, + 0x24840002, + 0x00021200, + 0x00220825, + 0x08001048, + 0xa4a10004, + 0x90820000, + 0x90810001, + 0x24840002, + 0x00010a00, + 0x00411025, + 0xa4a20002, + 0x90820000, + 0x90810001, + 0x24840002, + 0x00010a00, + 0x00411025, + 0x08001048, + 0xa4a2000a, + 0x90810000, + 0x90820001, + 0x24840002, + 0x00021200, + 0x00220825, + 0xa4a10002, + 0x90810000, + 0x90820001, + 0x24840002, + 0x00021200, + 0x00220825, + 0xa4a10004, + 0x90810000, + 0x90820001, + 0x90830002, + 0x00021200, + 0x00220825, + 0x00031c00, + 0x90820003, + 0x00230825, + 0x00021600, + 0x00220825, + 0x24840004, + 0x08001048, + 0xaca10010, + 0x90820000, + 0x90810001, + 0x24840002, + 0x00010a00, + 0x00411025, + 0xa4a20002, + 0x24a2000c, + 0xafa20004, + 0xafa40010, + 0xafa40008, + 0x0c0012b8, + 0xafa6000c, + 0x8fa10010, + 0x08001048, + 0x2424001c, + 0x2441ffed, + 0x1c20003c, + 0x00000027, + 0x1020ffd4, + 0x00000027, + 0x3841000f, + 0x1020ffd1, + 0x00000027, + 0x38410010, + 0x10200029, + 0x00000027, + 0x38410011, + 0x1020ffcb, + 0x00000027, + 0x38410012, + 0x10200003, + 0x00000027, + 0x08001039, + 0x00000027, + 0x90820000, + 0x90810001, + 0x24840002, + 0x00010a00, + 0x00411025, + 0xa4a20002, + 0x24a2000c, + 0xafa20004, + 0xafa40010, + 0xafa40008, + 0x0c0012b8, + 0xafa6000c, + 0x8fa5001c, + 0x8fa10010, + 0x00000027, + 0x2424001c, + 0x90820000, + 0x90810001, + 0x90830002, + 0x00010a00, + 0x00411025, + 0x00031c00, + 0x90810003, + 0x00431025, + 0x00010e00, + 0x00411025, + 0xaca20008, + 0x24810004, + 0x24240001, + 0x80210000, + 0x08001048, + 0xa0a10028, + 0x90820000, + 0x90810001, + 0x00000027, + 0x00010a00, + 0x00411025, + 0xa4a20002, + 0x24810002, + 0x24240001, + 0x80210000, + 0x08001048, + 0xa0a10028, + 0x38410014, + 0x1020003b, + 0x00000027, + 0x38410015, + 0x10200022, + 0x00000027, + 0x38410016, + 0x10200003, + 0x00000027, + 0x08001039, + 0x00000027, + 0x90820000, + 0x90810001, + 0x24840002, + 0x00010a00, + 0x00411025, + 0xa4a20002, + 0x90820000, + 0x90810001, + 0x90830002, + 0x00010a00, + 0x00411025, + 0x00031c00, + 0x90810003, + 0x00431025, + 0x00010e00, + 0x00411025, + 0xaca20008, + 0x24840008, + 0x90820000, + 0x90810001, + 0x24840002, + 0x00010a00, + 0x00411025, + 0xaca2000c, + 0xaca40010, + 0x8ca2000c, + 0x08001048, + 0x00822021, + 0x90810000, + 0x90820001, + 0x24840002, + 0x00021200, + 0x00220825, + 0xa4a10002, + 0x90810000, + 0x90820001, + 0x24840002, + 0x00021200, + 0x00220825, + 0xa4a10004, + 0x90810000, + 0x90820001, + 0x24840002, + 0x00021200, + 0x00220825, + 0xaca1000c, + 0xaca40010, + 0x8ca1000c, + 0x08001048, + 0x00812021, + 0x90820000, + 0x90810001, + 0x24840002, + 0x00010a00, + 0x00411025, + 0xa4a20002, + 0x90820000, + 0x90810001, + 0x90830002, + 0x00010a00, + 0x00411025, + 0x00031c00, + 0x90810003, + 0x00431025, + 0x00010e00, + 0x00411025, + 0xaca20008, + 0x24840008, + 0x90820000, + 0x90810001, + 0x24840002, + 0x00010a00, + 0x00411025, + 0x08001048, + 0xaca2000c, + 0x90820000, + 0x90810001, + 0x24840002, + 0x00010a00, + 0x00411025, + 0xa4a20002, + 0x90820000, + 0x90810001, + 0x24840002, + 0x00010a00, + 0x00411025, + 0xa4a20004, + 0x90820000, + 0x90810001, + 0x24840002, + 0x00010a00, + 0x00411025, + 0x08001048, + 0xaca2000c, + 0x2441ffe0, + 0x1c200059, + 0x00000027, + 0x1020004a, + 0x00000027, + 0x2441ffe4, + 0x1c200018, + 0x00000027, + 0x1020000f, + 0x00000027, + 0x38410018, + 0x1020000c, + 0x00000027, + 0x38410019, + 0x1020ff08, + 0x00000027, + 0x3841001a, + 0x1020ff38, + 0x00000027, + 0x3841001b, + 0x1020ff02, + 0x00000027, + 0x08001039, + 0x00000027, + 0x90810000, + 0x90820001, + 0x24840002, + 0x00021200, + 0x00220825, + 0x08001048, + 0xa4a10002, + 0x3841001d, + 0x10200018, + 0x00000027, + 0x3841001e, + 0x10200006, + 0x00000027, + 0x3841001f, + 0x1020fef0, + 0x00000027, + 0x08001039, + 0x00000027, + 0x90810000, + 0x90820001, + 0x24840002, + 0x00021200, + 0x00220825, + 0xa4a10002, + 0x24a10008, + 0xafa10004, + 0xafa40010, + 0xafa40008, + 0x0c0012b8, + 0xafa7000c, + 0x8fa20010, + 0x08001048, + 0x24440040, + 0x90820000, + 0x90810001, + 0x24840002, + 0x00010a00, + 0x00411025, + 0xa4a20002, + 0x90820000, + 0x90810001, + 0x24840002, + 0x00010a00, + 0x00411025, + 0xa4a20004, + 0x24a20008, + 0xafa20004, + 0xafa40010, + 0xafa40008, + 0x0c0012b8, + 0xafa7000c, + 0x8fa10010, + 0x08001048, + 0x24240040, + 0x90810000, + 0x90820001, + 0x24840002, + 0x00021200, + 0x00220825, + 0xa4a10002, + 0x90810000, + 0x90820001, + 0x24840002, + 0x00021200, + 0x00220825, + 0x08001048, + 0xa4a10004, + 0x2441ffdc, + 0x1c200045, + 0x00000027, + 0x1020ff75, + 0x00000027, + 0x38410021, + 0x1020002b, + 0x00000027, + 0x38410022, + 0x1020001b, + 0x00000027, + 0x38410023, + 0x10200003, + 0x00000027, + 0x08001039, + 0x00000027, + 0x90820000, + 0x90810001, + 0x24840002, + 0x00010a00, + 0x00411025, + 0xa4a20002, + 0x90820000, + 0x90810001, + 0x24840002, + 0x00010a00, + 0x00411025, + 0xa4a20004, + 0x24a20008, + 0xafa20004, + 0xafa40010, + 0xafa40008, + 0x0c0012b8, + 0xafa6000c, + 0x8fa10010, + 0x08001048, + 0x2424001c, + 0x90810000, + 0x90820001, + 0x24840002, + 0x00021200, + 0x00220825, + 0xa4a10002, + 0x90810000, + 0x90820001, + 0x24840002, + 0x00021200, + 0x00220825, + 0x08001048, + 0xa4a10008, + 0x90820000, + 0x90810001, + 0x24840002, + 0x00010a00, + 0x00411025, + 0xa4a20002, + 0x90820000, + 0x90810001, + 0x24840002, + 0x00010a00, + 0x00411025, + 0xa4a20004, + 0x24a20008, + 0xafa20004, + 0xafa40010, + 0xafa40008, + 0x0c0012b8, + 0xafa7000c, + 0x8fa10010, + 0x08001048, + 0x24240040, + 0x38410025, + 0x10200027, + 0x00000027, + 0x38410026, + 0x10200006, + 0x00000027, + 0x38410027, + 0x1020ff43, + 0x00000027, + 0x08001039, + 0x00000027, + 0x90810000, + 0x90820001, + 0x24840002, + 0x00021200, + 0x00220825, + 0xa4a10002, + 0x90810000, + 0x90820001, + 0x90830002, + 0x00021200, + 0x00220825, + 0x00031c00, + 0x90820003, + 0x00230825, + 0x00021600, + 0x00220825, + 0xaca10008, + 0x24840008, + 0x90810000, + 0x90820001, + 0x00000027, + 0x00021200, + 0x00220825, + 0xaca1000c, + 0x24820002, + 0x24440001, + 0xaca40010, + 0x8ca2000c, + 0x08001048, + 0x00822021, + 0x90820000, + 0x90810001, + 0x24840002, + 0x00010a00, + 0x00411025, + 0xa4a20002, + 0x90820000, + 0x90810001, + 0x24840002, + 0x00010a00, + 0x00411025, + 0xa4a20004, + 0x90820000, + 0x90810001, + 0x00000027, + 0x00010a00, + 0x00411025, + 0xaca2000c, + 0x24810002, + 0x24240001, + 0xaca40010, + 0x8ca1000c, + 0x08001048, + 0x00812021, + 0x23bdffec, + 0xafbf0000, + 0x8fa40018, + 0x8fa1001c, + 0x00000027, + 0xafa10004, + 0xafa40010, + 0xafa40008, + 0x2001001c, + 0x0c0012b8, + 0xafa1000c, + 0x8fa4001c, + 0x8fa20010, + 0x00000027, + 0x2445001c, + 0x90a10000, + 0x90a20001, + 0x90a30002, + 0x00021200, + 0x00220825, + 0x00031c00, + 0x90a20003, + 0x00230825, + 0x00021600, + 0x00220825, + 0xac81001c, + 0x24a20004, + 0x24450004, + 0x90a20000, + 0x90a10001, + 0x90a30002, + 0x00010a00, + 0x00411025, + 0x00031c00, + 0x90a10003, + 0x00431025, + 0x00010e00, + 0x00411025, + 0xac820024, + 0x24a50004, + 0x90a20000, + 0x90a10001, + 0x90a30002, + 0x00010a00, + 0x00411025, + 0x00031c00, + 0x90a10003, + 0x00431025, + 0x00010e00, + 0x00411025, + 0xac820028, + 0x24a50004, + 0x90a20000, + 0x90a10001, + 0x90a30002, + 0x00010a00, + 0x00411025, + 0x00031c00, + 0x90a10003, + 0x00431025, + 0x00010e00, + 0x00411025, + 0xac82002c, + 0x24a50004, + 0x90a20000, + 0x90a10001, + 0x90a30002, + 0x00010a00, + 0x00411025, + 0x00031c00, + 0x90a10003, + 0x00431025, + 0x00010e00, + 0x00411025, + 0xac820034, + 0x24a50008, + 0x90a20000, + 0x90a10001, + 0x24a50002, + 0x00010a00, + 0x00411025, + 0xa4820038, + 0x90a20000, + 0x90a10001, + 0x24a50002, + 0x00010a00, + 0x00411025, + 0xa482003a, + 0x90a20000, + 0x90a10001, + 0x24a50002, + 0x00010a00, + 0x00411025, + 0xa4820020, + 0x90a20000, + 0x90a10001, + 0x00000027, + 0x00010a00, + 0x00411025, + 0xa4820022, + 0x8fa20018, + 0x24a10002, + 0x00220823, + 0x8fa20000, + 0x00000027, + 0x00400008, + 0x23bd0014, + 0x23bdfffc, + 0x8fa30010, + 0x8fa40008, + 0x8fa5000c, + 0x00833021, + 0x28620004, + 0x00a4082b, + 0x14200036, + 0x00a33821, + 0x14400028, + 0x00000027, + 0x00a40826, + 0x30210003, + 0x14200024, + 0x00000027, + 0x30a10003, + 0x10200007, + 0x00000027, + 0x80a80000, + 0x24a50001, + 0xa0880000, + 0x30a10003, + 0x1420fffb, + 0x24840001, + 0x24e3fff1, + 0x00a3082b, + 0x1020000d, + 0x00000027, + 0x8ca80000, + 0x8ca90004, + 0xac880000, + 0x8ca80008, + 0xac890004, + 0x8ca9000c, + 0x24a50010, + 0xac880008, + 0xac89000c, + 0x00a3082b, + 0x1420fff5, + 0x24840010, + 0x24e3fffd, + 0x00a3082b, + 0x10200007, + 0x00000027, + 0x8ca80000, + 0x24a50004, + 0xac880000, + 0x00a3082b, + 0x1420fffb, + 0x24840004, + 0x00a7082b, + 0x10200007, + 0x00000027, + 0x80a80000, + 0x24a50001, + 0xa0880000, + 0x00a7082b, + 0x1420fffb, + 0x24840001, + 0x8fa10008, + 0x03e00008, + 0x23bd0004, + 0x14400028, + 0x00000027, + 0x00e60826, + 0x30210003, + 0x14200024, + 0x00000027, + 0x30e10003, + 0x10200007, + 0x00000027, + 0x80e8ffff, + 0x24e7ffff, + 0xa0c8ffff, + 0x30e10003, + 0x1420fffb, + 0x24c6ffff, + 0x24a3000f, + 0x0067082b, + 0x1020000d, + 0x00000027, + 0x8ce8fffc, + 0x8ce9fff8, + 0xacc8fffc, + 0x8ce8fff4, + 0xacc9fff8, + 0x8ce9fff0, + 0x24e7fff0, + 0xacc8fff4, + 0xacc9fff0, + 0x0067082b, + 0x1420fff5, + 0x24c6fff0, + 0x24a30003, + 0x0067082b, + 0x10200007, + 0x00000027, + 0x8ce8fffc, + 0x24e7fffc, + 0xacc8fffc, + 0x0067082b, + 0x1420fffb, + 0x24c6fffc, + 0x00a7082b, + 0x1020ffd2, + 0x00000027, + 0x80e8ffff, + 0x00000027, + 0xa0c8ffff, + 0x24c6ffff, + 0x0800131f, + 0x24e7ffff, + 0x23bdfffc, + 0x20010008, + 0x0000000c, + 0x03e00008, + 0x23bd0004, + 0x23bdfffc, + 0x20010002, + 0x0000000c, + 0x03e00008, + 0x23bd0004, + 0x23bdfffc, + 0x20010004, + 0x0000000c, + 0x03e00008, + 0x23bd0004, + 0x23bdfffc, + 0x20010016, + 0x0000000c, + 0x03e00008, + 0x23bd0004, + 0x23bdfffc, + 0x20010006, + 0x0000000c, + 0x03e00008, + 0x23bd0004, + 0x23bdfffc, + 0x20010007, + 0x0000000c, + 0x03e00008, + 0x23bd0004, + 0x23bdfffc, + 0x2001000d, + 0x0000000c, + 0x03e00008, + 0x23bd0004, + 0x23bdfffc, + 0x2001000e, + 0x0000000c, + 0x03e00008, + 0x23bd0004, + 0x23bdfffc, + 0x2001000f, + 0x0000000c, + 0x03e00008, + 0x23bd0004, + 0x23bdfffc, + 0x20010014, + 0x0000000c, + 0x03e00008, + 0x23bd0004, + 0x23bdfff4, + 0x3c017ff0, + 0xafa10004, + 0x20020001, + 0xafa20008, + 0xc7a10004, + 0xc7a00008, + 0x03e00008, + 0x23bd000c, + 0x23bdffe8, + 0xafbf0000, + 0xc7a5001c, + 0xc7a40020, + 0x3c037ff0, + 0xe7a50010, + 0xe7a40014, + 0x8fa10010, + 0x00000027, + 0x00230824, + 0x10230005, + 0x00000027, + 0x8fa20000, + 0x23bd0018, + 0x00400008, + 0x00000825, + 0xe7a50004, + 0xe7a40008, + 0x0c001392, + 0xafa0000c, + 0x14200005, + 0x00000027, + 0x8fa20000, + 0x23bd0018, + 0x00400008, + 0x20010001, + 0x8fa20000, + 0x23bd0018, + 0x00400008, + 0x00000825, + 0x23bdfff4, + 0x3c017ff0, + 0xafa10004, + 0xafa00008, + 0x8fa20010, + 0x00000027, + 0x04410006, + 0x00000027, + 0x8fa10004, + 0x00000027, + 0x3c1c8000, + 0x003c0825, + 0xafa10004, + 0xc7a10004, + 0xc7a00008, + 0x03e00008, + 0x23bd000c, + 0x23bdfff4, + 0x8fa30018, + 0xc7a30010, + 0xc7a20014, + 0x00000027, + 0xe7a30004, + 0xe7a20008, + 0x8fa10008, + 0x00000027, + 0x10200004, + 0x00000027, + 0x23bd000c, + 0x03e00008, + 0x00000825, + 0x8fa20004, + 0x3c017ff0, + 0x14410009, + 0x00000027, + 0x04600004, + 0x00000027, + 0x23bd000c, + 0x03e00008, + 0x20010001, + 0x23bd000c, + 0x03e00008, + 0x00000825, + 0x8fa20004, + 0x3c01fff0, + 0x14410009, + 0x00000027, + 0x1c600004, + 0x00000027, + 0x23bd000c, + 0x03e00008, + 0x20010001, + 0x23bd000c, + 0x03e00008, + 0x00000825, + 0x23bd000c, + 0x03e00008, + 0x00000825, + 0x00000000, + 0x00000000, + 0x00000001, + 0x0000000a, + 0x00000064, + 0x000003e8, + 0x00002710, + 0x000186a0, + 0x000f4240, + 0x00989680, + 0x05f5e100, + 0x3b9aca00, + 0x00000000, + 0x00000000, + 0x00000000, + 0x2a2a2a00, + 0x00000000, + 0x40240000, + 0x00000000, + 0x3fd34413, + 0x55475a32, + 0x6e6f6e2d, + 0x7a65726f, + 0x20657869, + 0x74207374, + 0x61747573, + 0x00000000, + 0x000051c4, + 0x000051c9, + 0x000051de, + 0x000051e5, + 0x000051fa, + 0x00005200, + 0x00005215, + 0x0000521d, + 0x00005232, + 0x00005236, + 0x0000524b, + 0x00005255, + 0x00000000, + 0x00000000, + 0x0000000d, + 0x62616420, + 0x74797065, + 0x3a202564, + 0x0a006261, + 0x64207479, + 0x70653a20, + 0x25640a00, + 0x00000000, + 0x001fffff, + 0x7fffffff, + 0x00002424, + 0x00002454, + 0x0000249c, + 0x000024ec, + 0x000024fc, + 0x0000252c, + 0x0000257c, + 0x000025c0, + 0x000025d0, + 0x00002620, + 0x00002ca4, + 0x00002d04, + 0x00002d64, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00090000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000001, + 0x020a0b0c, + 0x03000000, + 0x04000005, + 0x00000006, + 0x00070000, + 0x08000000, + 0x00000000, + 0x726f7373, + 0x00636f6e, + 0x6e656374, + 0x20303230, + 0x37303130, + 0x30356566, + 0x6600626f, + 0x6f746573, + 0x00636f6e, + 0x6e656374, + 0x20303830, + 0x30363930, + 0x32303230, + 0x35006865, + 0x6c697800, + 0x636f6e6e, + 0x65637420, + 0x30383030, + 0x36393032, + 0x30343237, + 0x00737069, + 0x6e646c65, + 0x00636f6e, + 0x6e656374, + 0x20303830, + 0x30363930, + 0x32303264, + 0x66007237, + 0x3000636f, + 0x6e6e6563, + 0x74203038, + 0x30303262, + 0x30343236, + 0x35640062, + 0x6974626f, + 0x6f746573, + 0x00626974, + 0x636f6e6e, + 0x65637400, + 0x3f006865, + 0x6c700025, + 0x730a0023, + 0x632f636f, + 0x6e730023, + 0x632f636f, + 0x6e730023, + 0x632f636f, + 0x6e730073, + 0x65727665, + 0x725b2573, + 0x5d3a2000, + 0x63616e27, + 0x74207265, + 0x61642023, + 0x632f636f, + 0x6e733b20, + 0x706c6561, + 0x73652072, + 0x65626f6f, + 0x74007573, + 0x65725b25, + 0x735d3a20, + 0x00626f6f, + 0x74657300, + 0x63616e27, + 0x74207265, + 0x61642023, + 0x632f636f, + 0x6e733b20, + 0x706c6561, + 0x73652072, + 0x65626f6f, + 0x7400626f, + 0x6f746573, + 0x00626f6f, + 0x74657300, + 0x23632f75, + 0x73657200, + 0x23632f75, + 0x73657200, + 0x75736572, + 0x20777269, + 0x74650062, + 0x6974636f, + 0x6e6e6563, + 0x74002362, + 0x2f626974, + 0x006f7065, + 0x6e696e67, + 0x2023622f, + 0x62697400, + 0x236c2f31, + 0x2f63746c, + 0x006f7065, + 0x6e696e67, + 0x20236c2f, + 0x312f6374, + 0x6c00636f, + 0x6e6e6563, + 0x74203078, + 0x39303000, + 0x636f6e6e, + 0x65637420, + 0x30783930, + 0x30007075, + 0x7368206e, + 0x6f657468, + 0x65720070, + 0x75736820, + 0x6e6f6574, + 0x68657200, + 0x236e2f31, + 0x2f646174, + 0x61006f70, + 0x656e696e, + 0x6720236e, + 0x2f312f64, + 0x61746100, + 0x236e2f31, + 0x2f63746c, + 0x006f7065, + 0x6e696e67, + 0x20236e2f, + 0x312f6374, + 0x6c006e6f, + 0x702e2e2e, + 0x00777269, + 0x7465206e, + 0x6f700072, + 0x65616420, + 0x6e6f7000, + 0x6e203d20, + 0x25643b20, + 0x62756620, + 0x3d20252e, + 0x32782025, + 0x2e327820, + 0x252e3278, + 0x20252e32, + 0x780a0066, + 0x6f726d61, + 0x74206e6f, + 0x70006e6f, + 0x7420526e, + 0x6f700073, + 0x65737369, + 0x6f6e2e2e, + 0x2e007772, + 0x69746520, + 0x73657373, + 0x696f6e00, + 0x72656164, + 0x20736573, + 0x73696f6e, + 0x00666f72, + 0x6d617420, + 0x73657373, + 0x696f6e00, + 0x6e6f7420, + 0x52736573, + 0x73696f6e, + 0x00657272, + 0x6f722025, + 0x643b0072, + 0x656d6f74, + 0x65206572, + 0x726f7200, + 0x706f7374, + 0x2e2e2e00, + 0x23732f25, + 0x73006372, + 0x65617465, + 0x00256400, + 0x77726974, + 0x65002373, + 0x2f257300, + 0x23732f62, + 0x6f6f7400, + 0x63726561, + 0x74650025, + 0x64007772, + 0x69746500, + 0x6d6f756e, + 0x742e2e2e, + 0x002f002f, + 0x0062696e, + 0x64002f00, + 0x006d6f75, + 0x6e740073, + 0x75636365, + 0x73730a00, + 0x2f6d6970, + 0x732f696e, + 0x69740069, + 0x6e697400, + 0x2f6d6970, + 0x732f696e, + 0x69740062, + 0x6f6f743a, + 0x2025733a, + 0x2025730a, + 0x00000000, + 0x00000000, + 0x00043e0, + 0x, + 0x00043e0, + 0x, +}; diff --git a/power/clock.c b/power/clock.c new file mode 100644 index 0000000000000000000000000000000000000000..26fe96ed34dfd23109155aade662541884aa0184 --- /dev/null +++ b/power/clock.c @@ -0,0 +1,190 @@ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" + +#include "ureg.h" + +Alarm *alarmtab; + +Alarm* +alarm(int ms, void (*f)(Alarm*), void *arg) +{ + Alarm *a, *w, *pw; + ulong s; + if(ms < 0) + ms = 0; + a = newalarm(); + a->dt = ms/MS2HZ; + a->f = f; + a->arg = arg; + s = splhi(); + lock(&m->alarmlock); + pw = 0; + for(w=m->alarm; w; pw=w, w=w->next){ + if(w->dt <= a->dt){ + a->dt -= w->dt; + continue; + } + w->dt -= a->dt; + break; + } + insert(&m->alarm, pw, a); + unlock(&m->alarmlock); + splx(s); + return a; +} + +void +cancel(Alarm *a) +{ + a->f = 0; +} + +Alarm* +newalarm(void) +{ + int i; + Alarm *a; + + for(i=0,a=alarmtab; ibusy==0 && a->f==0 && canlock(a)){ + if(a->busy){ + unlock(a); + continue; + } + a->f = 0; + a->arg = 0; + a->busy = 1; + unlock(a); + return a; + } + panic("newalarm"); +} + +void +alarminit(void) +{ + int i; + + alarmtab = ialloc(conf.nalarm*sizeof(Alarm), 0); + for(i=0; ictl = CTR(2)|SET16|MODE2; + t->cnt2 = TIME2&0xFF; + t->cnt2 = (TIME2>>8)&0xFF; + t->ctl = CTR(1)|SET16|MODE2; + t->cnt1 = TIME1&0xFF; + t->cnt1 = (TIME1>>8)&0xFF; + t->ctl = CTR(0)|SET16|MODE2; + t->cnt0 = TIME0; + t->cnt0 = (TIME0>>8)&0xFF; + i = *CLRTIM0; + i = *CLRTIM1; + m->ticks = 0; +} + +void +clock(ulong n) +{ + int i; + Alarm *a; + void (*f)(void*); + Proc *p; + + if(n&INTR2){ + i = *CLRTIM0; + m->ticks++; + if(m->machno == 0){ + p = m->proc; + if(p == 0) + p = m->intrp; + if(p) + p->time[p->insyscall]++; + for(i=1; iproc; + if(p && p!=m->intrp) + p->time[p->insyscall]++; + } + } + m->intrp = 0; + printslave(); + } + if(active.exiting && active.machs&(1<machno)){ + print("someone's exiting\n"); + exit(); + } + if(canlock(&m->alarmlock)){ + if(m->alarm){ + a = m->alarm; + a->dt--; + while(a && a->dt<=0){ + f = a->f; /* avoid race with cancel */ + if(f) + (*f)(a); + delete(&m->alarm, 0, a); + a->busy = 0; + a = m->alarm; + } + } + unlock(&m->alarmlock); + } + return; + } + if(n & INTR4){ + i = *CLRTIM1; + return; + } +} diff --git a/power/dat.h b/power/dat.h new file mode 100644 index 0000000000000000000000000000000000000000..5f44a9df4526d0c4fcc2d0f9a28c263e9cfcdbbb --- /dev/null +++ b/power/dat.h @@ -0,0 +1,528 @@ +typedef struct Alarm Alarm; +typedef struct Blist Blist; +typedef struct Block Block; +typedef struct Chan Chan; +typedef struct Conf Conf; +typedef struct Dev Dev; +typedef struct Dirtab Dirtab; +typedef struct Env Env; +typedef struct Envp Envp; +typedef struct Envval Envval; +typedef struct Error Error; +typedef struct FPsave FPsave; +typedef struct Label Label; +typedef struct List List; +typedef struct Lock Lock; +typedef struct Mach Mach; +typedef struct Mount Mount; +typedef struct Mtab Mtab; +typedef struct Note Note; +typedef struct Orig Orig; +typedef struct PTE PTE; +typedef struct Page Page; +typedef struct Pgrp Pgrp; +typedef struct Proc Proc; +typedef struct QLock QLock; +typedef struct Qinfo Qinfo; +typedef struct Queue Queue; +typedef struct Stream Stream; +typedef struct Ref Ref; +typedef struct Rendez Rendez; +typedef struct Seg Seg; +typedef struct Ureg Ureg; +typedef struct User User; + +typedef int Devgen(Chan*, Dirtab*, int, int, Dir*); + +struct List +{ + void *next; +}; + +struct Lock +{ + ulong *sbsem; /* addr of sync bus semaphore */ + ulong pc; +}; + +struct Ref +{ + Lock; + int ref; +}; + +struct QLock +{ + Proc *head; /* next process waiting for object */ + Proc *tail; /* last process waiting for object */ + Lock use; /* to use object */ + Lock queue; /* to access list */ +}; + +struct Label +{ + ulong pc; + ulong sp; +}; + +struct Alarm +{ + List; + Lock; + int busy; + long dt; /* may underflow in clock(); must be signed */ + void (*f)(void*); + void *arg; +}; + +#define CHDIR 0x80000000L +#define QPATH 0x0000FFFFL +struct Chan +{ + QLock; /* general access */ + Ref; + union{ + Chan *next; /* allocation */ + ulong offset; /* in file */ + }; + ushort type; + ushort dev; + ushort mode; /* read/write */ + ushort flag; + ulong qid; + Mount *mnt; /* mount point that derived Chan */ + ulong mountid; + int fid; /* for devmnt */ + Stream *stream; /* for stream channels */ +}; + +struct FPsave +{ + long fpreg[32]; + long fpstatus; +}; + +struct Conf +{ + int nmach; /* processors */ + int nproc; /* processes */ + int npgrp; /* process groups */ + ulong npage; /* total physical pages of memory */ + ulong norig; /* origins */ + ulong npte; /* contiguous page table entries */ + ulong nmod; /* single (modifying) page table entries */ + int nalarm; /* alarms */ + int nchan; /* channels */ + int nenv; /* distinct environment values */ + int nenvchar; /* environment text storage */ + int npgenv; /* environment files per process group */ + int nmtab; /* mounted-upon channels per process group */ + int nmount; /* mounts */ + int nmntdev; /* mounted devices (devmnt.c) */ + int nmntbuf; /* buffers for devmnt.c messages */ + int nmnthdr; /* headers for devmnt.c messages */ + int nstream; /* streams */ + int nqueue; /* stream queues */ + int nblock; /* stream blocks */ + int nsrv; /* public servers (devsrv.c) */ +}; + +struct Dev +{ + void (*reset)(void); + void (*init)(void); + Chan *(*attach)(char*); + Chan *(*clone)(Chan*, Chan*); + int (*walk)(Chan*, char*); + void (*stat)(Chan*, char*); + Chan *(*open)(Chan*, int); + void (*create)(Chan*, char*, int, ulong); + void (*close)(Chan*); + long (*read)(Chan*, void*, long); + long (*write)(Chan*, void*, long); + void (*remove)(Chan*); + void (*wstat)(Chan*, char*); + void (*errstr)(Error*, char*); + void (*userstr)(Error*, char*); +}; + +struct Dirtab +{ + char name[NAMELEN]; + long qid; + long length; + long perm; +}; + +struct Env +{ + Lock; + Envval *val; + char name[NAMELEN]; + Env *next; /* in chain of Envs for a pgrp */ + int pgref; /* # pgrps pointing here */ +}; + +struct Envp +{ + Env *env; + int chref; /* # chans from pgrp pointing here */ +}; + +struct Mach +{ + int machno; /* physical id of processor */ + int mmask; /* 1<machno */ + ulong ticks; /* of the clock since boot time */ + Proc *proc; /* current process on this processor */ + Label sched; /* scheduler wakeup */ + Lock alarmlock; /* access to alarm list */ + void *alarm; /* alarms bound to this clock */ + void (*intr)(ulong); /* pending interrupt */ + Proc *intrp; /* process that was interrupted */ + ulong cause; /* arg to intr */ + char pidhere[NTLBPID]; /* is this pid possibly in this mmu? */ + int lastpid; /* last pid allocated on this machine */ + Proc *pidproc[NTLBPID]; /* process that owns this tlbpid on this mach */ + int stack[1]; +}; + +struct Mount +{ + Ref; /* also used as a lock when playing lists */ + short term; /* terminates list */ + ulong mountid; + Mount *next; + Chan *c; /* channel replacing underlying channel */ +}; + +struct Mtab +{ + Chan *c; /* channel mounted upon */ + Mount *mnt; /* what's mounted upon it */ +}; + +enum{ + NUser, /* note provided externally */ + NExit, /* process should exit */ + NDebug, /* process should hang */ +}; + +struct Note +{ + char msg[ERRLEN]; + int flag; /* whether system posted it */ +}; + +struct Orig +{ + Lock; + Orig *next; /* for allocation */ + ushort nproc; /* processes using it */ + ushort npage; /* sum of refs of pages in it */ + ushort flag; + ulong va; /* va of 0th pte */ + ulong npte; /* #pte's in list */ + PTE *pte; + Chan *chan; /* channel deriving segment (if open) */ + ushort type; /* of channel (which could be non-open) */ + ushort dev; + ulong qid; + ulong minca; /* base of region in chan */ + ulong maxca; /* end of region in chan */ +}; + +struct Page +{ + Orig *o; /* origin of segment owning page */ + ulong va; /* virtual address */ + ulong pa; /* physical address */ + ushort ref; + Page *next; + Page *prev; +}; + +struct Pgrp +{ + Ref; /* also used as a lock when mounting */ + Pgrp *next; + ulong pgrpid; + char user[NAMELEN]; + int nmtab; /* highest active mount table entry, +1 */ + int nenv; /* highest active env table entry, +1 */ + Mtab *mtab; + Envp *etab; +}; + +struct PTE +{ + Proc *proc; /* process owning this PTE (0 in Orig) */ + PTE *nextmod; /* next at this va */ + PTE *nextva; /* next in this proc at higher va */ + Page *page; +}; + +struct Rendez +{ + Lock; + Proc *p; +}; + +struct Seg +{ + Proc *proc; /* process owning this segment */ + Orig *o; /* root list of pte's */ + ulong minva; /* va of 0th pte (not necessarily Seg->o->va) */ + ulong maxva; /* va of last pte */ + PTE *mod; /* list of modified pte's */ + ulong pad[3]; /**/ +}; + +struct Proc +{ + Label sched; + Mach *mach; /* machine running this proc */ + char text[NAMELEN]; + Proc *rnext; /* next process in run queue */ + Proc *qnext; /* next process on queue for a QLock */ + int state; + short pidonmach[MAXMACH]; /* TLB pid on each mmu */ + Page *upage; /* BUG: should be unlinked from page list */ + Seg seg[NSEG]; + ulong pid; + int nchild; + QLock wait; /* exiting children to be waited for */ + Waitmsg *waitmsg; + Proc *child; + Proc *parent; + Pgrp *pgrp; + ulong parentpid; + ulong time[6]; /* User, Sys, Real; child U, S, R */ + short exiting; + short insyscall; + int fpstate; + Lock debug; /* to access debugging elements of User */ + Rendez *r; /* rendezvous point slept on */ + Rendez sleep; /* place for tsleep and syssleep */ + int wokeup; /* whether sleep was interrupted */ + ulong pc; /* DEBUG only */ + +}; + +#define NERR 15 +#define NFD 100 +#define NNOTE 5 +struct User +{ + Proc *p; + Label errlab[NERR]; + int nerrlab; + Error error; + FPsave fpsave; /* address of this is known by vdb */ + char elem[NAMELEN]; /* last name element from namec */ + Chan *slash; + Chan *dot; + Chan *fd[NFD]; + int maxfd; /* highest fd in use */ + /* + * Rest of structure controlled by devproc.c and friends. + * lock(&p->debug) to modify. + */ + Note note[NNOTE]; + short nnote; + short notified; /* sysnoted is due */ + int (*notify)(void*, char*); + void *ureg; +}; + +/* + * operations available to a queue + */ +struct Qinfo +{ + void (*iput)(Queue*, Block*); /* input routine */ + void (*oput)(Queue*, Block*); /* output routine */ + void (*open)(Queue*, Stream*); + void (*close)(Queue*); + char *name; +}; + +/* + * We reference lance buffers via descriptors kept in host memory + */ +struct Block +{ + Block *next; + uchar *rptr; /* first unconsumed byte */ + uchar *wptr; /* first empty byte */ + uchar *lim; /* 1 past the end of the buffer */ + uchar *base; /* start of the buffer */ + uchar flags; + uchar type; +}; + +/* flag bits */ +#define S_DELIM 0x80 +#define S_CLASS 0x07 + +/* type values */ +#define M_DATA 0 +#define M_CTL 1 +#define M_HANGUP 2 + +/* + * a list of blocks + */ +struct Blist { + Lock; + Block *first; /* first data block */ + Block *last; /* last data block */ + long len; /* length of list in bytes */ +}; + +/* + * a queue of blocks + */ +struct Queue { + Blist; + int flag; + Qinfo *info; /* line discipline definition */ + Queue *other; /* opposite direction, same line discipline */ + Queue *next; /* next queue in the stream */ + void (*put)(Queue*, Block*); + Rendez r; + void *ptr; /* private info for the queue */ +}; +#define QHUNGUP 0x1 /* flag bit meaning the stream has been hung up */ +#define QINUSE 0x2 +#define QHIWAT 0x4 /* queue has gone past the high water mark */ + +/* + * a stream head + */ +struct Stream { + Lock; /* structure lock */ + int inuse; /* use count */ + int type; /* correclation with Chan */ + int dev; /* ... */ + int id; /* ... */ + QLock rdlock; /* read lock */ + QLock wrlock; /* write lock */ + Queue *procq; /* write queue at process end */ + Queue *devq; /* read queue at device end */ + char tag[32]; /* when reading the tag qid */ +}; +#define RD(q) ((q)->other < (q) ? (q->other) : q) +#define WR(q) ((q)->other > (q) ? (q->other) : q) +#define GLOBAL(a) (((ulong)(a)) & 0x80000000) +#define STREAMTYPE(x) ((x)&0x1f) +#define STREAMID(x) (((x)&~CHDIR)>>5) +#define STREAMQID(i,t) (((i)<<5)|(t)) +#define PUTNEXT(q,b) (*(q)->next->put)((q)->next, bp) + +/* + * stream file qid's & high water mark + */ +enum { + Shighqid = STREAMQID(1,0) - 1, + Sdataqid = Shighqid, + Sctlqid = Sdataqid-1, + Slowqid = Sctlqid, + Streamhi= (32*1024), /* stream high water mark */ +}; + +#define PRINTSIZE 256 +struct +{ + Lock; + short machs; + short exiting; +}active; + +extern register Mach *m; +extern register User *u; + +/* + * Process states + */ +enum +{ + Dead = 0, + Moribund, + Zombie, + Ready, + Scheding, + Running, + Queueing, + MMUing, + Exiting, + Inwait, + Wakeme, + Broken, +}; +extern char *statename[]; + +/* + * Chan flags + */ +#define COPEN 1 /* for i/o */ +#define CMOUNT 2 /* is result of a mount/bind */ +#define CCREATE 4 /* permits creation if CMOUNT */ + +/* + * Proc.time + */ +enum +{ + TUser, + TSys, + TReal, + TCUser, + TCSys, + TCReal, +}; + +/* + * floating point registers + */ +enum +{ + FPinit, + FPactive, + FPinactive, +}; + +/* + * Memory management + */ +#define SSEG 0 +#define TSEG 1 +#define DSEG 2 +#define BSEG 3 +#define ESEG 4 /* used by exec to build new stack */ + +#define OWRPERM 0x01 /* write permission */ +#define OPURE 0x02 /* original data mustn't be written */ +#define OCACHED 0x04 /* cached; don't discard on exit */ + +/* + * Access types in namec + */ +enum +{ + Aaccess, /* as in access, stat */ + Atodir, /* as in chdir */ + Aopen, /* for i/o */ + Amount, /* to be mounted upon */ + Acreate, /* file is to be created */ +}; + +#define NUMSIZE 12 /* size of formatted number */ + +#define MACHP(n) ((Mach *)(MACHADDR+n*BY2PG)) + +extern Conf conf; +extern ulong initcode[]; +extern Dev devtab[]; +extern char devchar[]; +extern FPsave initfp; diff --git a/power/devbit.c b/power/devbit.c new file mode 100644 index 0000000000000000000000000000000000000000..7a0de965987a4db882818ff5ea30d41e04996041 --- /dev/null +++ b/power/devbit.c @@ -0,0 +1,215 @@ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "errno.h" +#include "devtab.h" + +#include "io.h" + +typedef struct Bitmsg Bitmsg; +struct Bitmsg +{ + ulong cmd; + ulong addr; + ulong count; + ulong result; +}; + +static struct +{ + QLock; + int open; + Bitmsg msg; + char buf[10*1024]; +}bit; + +#define BITADDR ((Bitmsg**)(KZERO+0x7C)) +#define BITINTR ((char*)(UNCACHED|0x17c12001)) + +enum +{ + RESET, + READ, + WRITE, +}; + +void +bitsend(ulong cmd, void *addr, ulong count) +{ + bit.msg.cmd = cmd; + bit.msg.addr = (ulong)addr; + bit.msg.count = count; + if(*BITADDR) + panic("bitsend"); + *BITADDR = &bit.msg; + wbflush(); + *BITINTR = 0x20; +} + +void +bitsync(void) +{ + while(*BITADDR) + ; +} + +void +bitreset(void) +{ + *BITADDR = 0; + qlock(&bit); + qunlock(&bit); +} + +void +bitinit(void) +{ +} + +Chan* +bitattach(char *spec) +{ + return devattach('b', spec); +} + +Chan* +bitclone(Chan *c, Chan *nc) +{ + return devclone(c, nc); +} + +int +bitwalk(Chan *c, char *name) +{ + if(c->qid != CHDIR) + return 0; + if(strcmp(name, "bit") == 0){ + c->qid = 1; + return 1; + } + return 0; +} + +void +bitstat(Chan *c, char *dp) +{ + print("bitstat\n"); + error(0, Egreg); +} + +Chan* +bitopen(Chan *c, int omode) +{ + if(c->qid!=1 || omode!=ORDWR) + error(0, Eperm); + qlock(&bit); + if(bit.open){ + qunlock(&bit); +print("multiple bit open\n"); + error(0, Einuse); + } + bitsync(); + bitsend(RESET, 0, 0); + bitsync(); + bit.open = 1; + qunlock(&bit); + c->mode = openmode(omode); + c->flag |= COPEN; + c->offset = 0; + return c; +} + +void +bitcreate(Chan *c, char *name, int omode, ulong perm) +{ + error(0, Eperm); +} + +void +bitclose(Chan *c) +{ + qlock(&bit); + bit.open = 0; + qunlock(&bit); +} + +/* + * Read and write use physical addresses if they can, which they usually can. + * Most I/O is from devmnt, which has local buffers. Therefore just check + * that buf is in KSEG0 and is at an even address. The only killer is that + * DMA counts from the bit device are mod 256, so devmnt must use oversize + * buffers. + */ + +long +bitread(Chan *c, void *buf, long n) +{ + switch(c->qid){ + case 1: + if(n > sizeof bit.buf) + error(0, Egreg); + qlock(&bit); + if((((ulong)buf)&(KSEGM|3)) == KSEG0){ + bitsend(READ, buf, n); + bitsync(); + }else{ + bitsend(READ, bit.buf, n); + bitsync(); + memcpy(buf, bit.buf, n); + } + n = bit.msg.result; + qunlock(&bit); + return n; + } + error(0, Egreg); + return 0; +} + +long +bitwrite(Chan *c, void *buf, long n) +{ + switch(c->qid){ + case 1: + if(n > sizeof bit.buf) + error(0, Egreg); + qlock(&bit); + if((((ulong)buf)&(KSEGM|3)) == KSEG0){ + bitsend(WRITE, buf, n); + bitsync(); + }else{ + memcpy(bit.buf, buf, n); + bitsend(WRITE, bit.buf, n); + bitsync(); + } + qunlock(&bit); + return n; + } + error(0, Egreg); + return 0; +} + +void +bitremove(Chan *c) +{ + error(0, Eperm); +} + +void +bitwstat(Chan *c, char *dp) +{ + error(0, Eperm); +} + +void +bituserstr(Error *e, char *buf) +{ + consuserstr(e, buf); +} + +void +biterrstr(Error *e, char *buf) +{ + rooterrstr(e, buf); +} diff --git a/power/devhs.c b/power/devhs.c new file mode 100644 index 0000000000000000000000000000000000000000..91f5665a3cbb6cbe90f8129779fa97b6687c751b --- /dev/null +++ b/power/devhs.c @@ -0,0 +1,227 @@ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "errno.h" +#include "devtab.h" + +#include "io.h" + +enum { + Maxtxburst= 1024, /* maximum transmit burst size */ + Vmevec= 0xd0, /* vme vector for interrupts */ + Intlevel= 5, /* level to interrupt on */ +}; + +struct hsvmestats { + ulong parity; + ulong rintr; + ulong tintr; +} hsvmestats; + +#define ALIVE 0x0001 +#define IENABLE 0x0004 +#define EXOFLOW 0x0008 +#define IRQ 0x0010 +#define EMUTE 0x0020 +#define EPARITY 0x0040 +#define EFRAME 0x0080 +#define EROFLOW 0x0100 +#define REF 0x0800 +#define XFF 0x4000 +#define XHF 0x8000 + +#define FORCEW 0x0008 +#define IPL(x) ((x)<<5) +#define NORESET 0xFF00 +#define RESET 0x0000 + +#define CTL 0x0100 +#define CHNO 0x0200 +#define TXEOD 0x0400 +#define NND 0x8000 + +Rendez hsvmer; + +#define DELAY(n) { \ + register int N = 12*(n); \ + while (--N > 0); \ + } + +static void hsvmeintr(int); + +void +hsvmerestart(struct hsvme *addr) +{ + addr->csr = RESET; + wbflush(); + DELAY(20000); + + /* + * set interrupt vector + * turn on addrice + * set forcew to a known value + * interrupt on level `Intlevel' + */ + addr->vector = 0xd0; + addr->csr = NORESET|IPL(Intlevel)|IENABLE|ALIVE; + wbflush(); + DELAY(500); + addr->csr = NORESET|IPL(Intlevel)|FORCEW|IENABLE|ALIVE; + wbflush(); + DELAY(500); +} + +void +hsvmereset(void) +{ + struct hsvme *addr; + + addr = HSVME; + addr->csr = RESET; + wbflush(); + DELAY(20000); + + /* + * routine to call on interrupt + */ + setvmevec(Vmevec, hsvmeintr); +} + +void +hsvmeinit(void) +{ +} + +/* + * enable the device for interrupts + */ +static int +never(void *arg) +{ + return 0; +} +Chan* +hsvmeattach(char *spec) +{ + struct hsvme *addr; + + addr = HSVME; + hsvmerestart(addr); + print("hsvme csr %ux\n", addr->csr); + + return devattach('h', spec); +} + +Chan* +hsvmeclone(Chan *c, Chan *nc) +{ + return devclone(c, nc); +} + +int +hsvmewalk(Chan *c, char *name) +{ + if(c->qid != CHDIR) + return 0; + if(strcmp(name, "hsvme") == 0){ + c->qid = 1; + return 1; + } + return 0; +} + +void +hsvmestat(Chan *c, char *dp) +{ + print("hsvmestat\n"); + error(0, Egreg); +} + +Chan* +hsvmeopen(Chan *c, int omode) +{ + c->mode = openmode(omode); + c->flag |= COPEN; + c->offset = 0; + return c; +} + +void +hsvmecreate(Chan *c, char *name, int omode, ulong perm) +{ + error(0, Eperm); +} + +void +hsvmeclose(Chan *c) +{ +} + +long +hsvmeread(Chan *c, void *buf, long n) +{ + error(0, Egreg); + return 0; +} + +long +hsvmewrite(Chan *c, void *buf, long n) +{ + error(0, Egreg); + return 0; +} + +void +hsvmeremove(Chan *c) +{ + error(0, Eperm); +} + +void +hsvmewstat(Chan *c, char *dp) +{ + error(0, Eperm); +} + +void +hsvmeuserstr(Error *e, char *buf) +{ + consuserstr(e, buf); +} + +void +hsvmeerrstr(Error *e, char *buf) +{ + rooterrstr(e, buf); +} + +static void +hsvmeintr(int vec) +{ + ushort csr; + struct hsvme *addr; + + print("hsvme intr\n"); + addr = HSVME; + wbflush(); + csr = addr->csr; + do { + if (addr->csr & REF) { + hsvmestats.rintr++; + print("hsvme rintr\n"); + } + if (addr->csr & XHF) { + hsvmestats.tintr++; + print("hsvme tintr\n"); + } + if ((csr^XFF) & (XFF|EROFLOW|EFRAME|EPARITY|EXOFLOW)) { + hsvmestats.parity++; + hsvmerestart(addr); + print("hsvme %ux: reset, csr = 0x%x\n", + HSVME, csr); + } + wbflush(); + } while ((csr = addr->csr) & REF); +} diff --git a/power/duart.c b/power/duart.c new file mode 100644 index 0000000000000000000000000000000000000000..195d16f065dbf348fe6accabe4fd9a7baadfd1b6 --- /dev/null +++ b/power/duart.c @@ -0,0 +1,204 @@ +#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; + switch(c &= 0x7F){ + case 0x10: + panic("^p"); + } + 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; +} diff --git a/power/errno.h b/power/errno.h new file mode 100644 index 0000000000000000000000000000000000000000..9e8c2fb90810941ce401a6153144ce7a35f8e7aa --- /dev/null +++ b/power/errno.h @@ -0,0 +1,45 @@ +enum{ + Enevermind, /* never mind */ + Enofd, /* no free file descriptors */ + Ebadfd, /* fd out of range or not open */ + Ebadusefd, /* inappropriate use of fd */ + Ebadarg, /* bad arg in system call */ + Enonexist, /* file does not exist */ + Efilename, /* file name syntax */ + Ebadchar, /* bad character in file name */ + Ebadsharp, /* unknown device in # filename */ + Ebadexec, /* a.out header invalid */ + Eioload, /* i/o error in demand load */ + Eperm, /* permission denied */ + Enotdir, /* not a directory */ + Enochild, /* no living children */ + Enoseg, /* no free segments */ + Ebadmount, /* inconsistent mount */ + Enomount, /* mount table full */ + Enomntdev, /* no free mount devices */ + Eshutdown, /* mounted device shut down */ + Einuse, /* device or object already in use */ + Eio, /* i/o error */ + Eisdir, /* file is a directory */ + Ebaddirread, /* directory read not quantized */ + Esegaddr, /* illegal segment addresses or size */ + Enoenv, /* no free environment resources */ + Eprocdied, /* process exited */ + Enocreate, /* mounted directory forbids creation */ + Enotunion, /* attempt to union with non-mounted directory */ + Emount, /* inconsistent mount */ + Enosrv, /* no free server slots */ + Enoqueue, /* no free stream queues */ + Ebadld, /* illegal line discipline */ + Enostream, /* no free stream heads */ + Etoobig, /* read or write too large */ + Etoosmall, /* read or write too small */ + Ehungup, /* write to hungup stream */ + Ebadnet, /* illegal network address */ + Enoifc, /* no free nonet interface slots */ + Enodev, /* no free devices */ + Ebadctl, /* bad process control request */ + Enonote, /* note overflow */ + Eintr, /* interrupted */ + Egreg, /* it's all greg's fault */ +}; diff --git a/power/fcall.h b/power/fcall.h new file mode 100644 index 0000000000000000000000000000000000000000..a61e67b833ffd0ff566cfd35cde4c1012acd0583 --- /dev/null +++ b/power/fcall.h @@ -0,0 +1,89 @@ +typedef struct Fcall Fcall; + +struct Fcall +{ + char type; + short fid; + short err; + union + { + struct + { + short uid; /* T-Userstr */ + short newfid; /* T-Clone */ + char lang; /* T-Session */ + ulong qid; /* R-Attach, R-Walk, R-Open, R-Create */ + }; + struct + { + char uname[28]; /* T-Attach, R-Userstr */ + char aname[28]; /* T-Attach */ + }; + struct + { + char ename[64]; /* R-Errstr */ + }; + struct + { + long perm; /* T-Create */ + char name[28]; /* T-Walk, T-Create, T-Remove */ + char mode; /* T-Create, T-Open */ + }; + struct + { + long offset; /* T-Read, T-Write */ + long count; /* T-Read, T-Write, R-Read */ + char *data; /* T-Write, R-Read */ + }; + struct + { + char stat[DIRLEN]; /* T-Wstat, R-Stat */ + }; + }; +}; + +#define MAXFDATA 8192 + +enum +{ + Tnop = 0, + Rnop, + Tsession = 2, + Rsession, + Tattach = 10, + Rattach, + Tclone = 12, + Rclone, + Twalk = 14, + Rwalk, + Topen = 16, + Ropen, + Tcreate = 18, + Rcreate, + Toread = 20, + Roread, + Towrite = 22, + Rowrite, + Tclunk = 24, + Rclunk, + Tremove = 26, + Rremove, + Tstat = 28, + Rstat, + Twstat = 30, + Rwstat, + Terrstr = 32, + Rerrstr, + Tuserstr = 34, + Ruserstr, + Tread = 36, + Rread, + Twrite = 38, + Rwrite, +}; + +int convM2S(char*, Fcall*, int); +int convS2M(Fcall*, char*); + +int convM2D(char*, Dir*); +int convD2M(Dir*, char*); diff --git a/power/fns.h b/power/fns.h new file mode 100644 index 0000000000000000000000000000000000000000..2a039f7575fa2344213e1cf682578986c1073df2 --- /dev/null +++ b/power/fns.h @@ -0,0 +1,174 @@ +Alarm *alarm(int, void (*)(Alarm*), void*); +void alarminit(void); +Block *allocb(ulong); +void append(List**, List*); +void cancel(Alarm*); +int canlock(Lock*); +int canqlock(QLock*); +void chaninit(void); +void chandevreset(void); +void chandevinit(void); +void clock(ulong); +void clockinit(void); +Chan *clone(Chan*, Chan*); +void close(Chan*); +void closemount(Mount*); +void closepgrp(Pgrp*); +long clrfpintr(void); +void compactpte(Orig*, ulong); +void confinit(void); +int consactive(void); +int conschar(void); +void consoff(void); +int consputc(int); +Env *copyenv(Env*, int); +int decref(Ref*); +void delay(int); +void delete(List**, List*, List*); +void delete0(List**, List*); +Chan *devattach(int, char*); +Chan *devclone(Chan*, Chan*); +void devdir(Chan*, long, char*, long, long, Dir*); +long devdirread(Chan*, char*, long, Dirtab*, int, Devgen*); +Devgen devgen; +int devno(int, int); +Chan* devopen(Chan*, int, Dirtab*, int, Devgen*); +void devstat(Chan*, char*, Dirtab*, int, Devgen*); +int devwalk(Chan*, char*, Dirtab*, int, Devgen*); +void duartinit(void); +void duartintr(void); +int duartputc(int); +void duartreset(void); +void duartxmit(int); +void dumpregs(Ureg*); +void dumpstack(void); +int eqchan(Chan*, Chan*, long); +void envpgclose(Env*); +void error(Chan*, int); +void evenaddr(ulong); +void exit(void); +void fault(Ureg*, int, int); +Chan* fdtochan(int, int); +void firmware(void); +void flowctl(Queue*); +void flushmmu(void); +void forkmod(Seg*, Seg*, Proc*); +void freeb(Block*); +void freepage(Orig*); +void freepte(Orig*); +void freesegs(int); +void freealarm(Alarm*); +Block *getb(Blist*); +Block *getq(Queue*); +void gettlb(int, ulong*); +ulong gettlbvirt(int); +void gotolabel(Label*); +void growpte(Orig*, ulong); +void *ialloc(ulong, int); +int incref(Ref*); +void insert(List**, List*, List*); +void intr(ulong); +void io2init(void); +void isdir(Chan*); +void kbdchar(int); +void kproc(char*, void(*)(void*), void*); +void launchinit(void); +void lancereset(void); +void lanceinit(void); +void lanceintr(void); +void lanceparity(void); +void lanceinit(void); +void launch(int); +void lights(int); +void lock(Lock*); +void lockinit(void); +Orig *lookorig(ulong, ulong, int, Chan*); +void machinit(void); +void mapstack(Proc*); +int mount(Chan*, Chan*, int); +Chan *namec(char*, int, int, ulong); +void nexterror(void); +Alarm *newalarm(void); +Chan *newchan(void); +PTE *newmod(void); +Mount *newmount(void); +Orig *neworig(ulong, ulong, int, Chan*); +Page *newpage(int, Orig*, ulong); +Pgrp *newpgrp(void); +Proc *newproc(void); +char *nextelem(char*, char*); +void newstart(void); +int newtlbpid(Proc*); +void novme(int); +void nullput(Queue*, Block*); +void online(void); +int openmode(ulong); +void pageinit(void); +void panic(char*, ...); +void pexit(char*, int); +void pgrpcpy(Pgrp*, Pgrp*); +void pgrpinit(void); +int postnote(Proc*, int, char*, int); +int pprint(char*, ...); +void prflush(void); +void printinit(void); +void printslave(void); +void procinit0(void); +Proc *proctab(int); +void purgetlb(int); +Queue* pushq(Stream*, Qinfo*); +void putmmu(ulong, ulong); +void puttlb(ulong, ulong); +void puttlbx(int, ulong, ulong); +int putb(Blist*, Block*); +int putq(Queue*, Block*); +void putstrn(char*, long); +ulong pwait(Waitmsg*); +int readnum(ulong, char*, ulong, ulong, int); +void ready(Proc*); +void rooterrstr(Error*, char*); +void qlock(QLock*); +void qunlock(QLock*); +void restfpregs(FPsave*); +int return0(void*); +Proc *runproc(void); +void savefpregs(FPsave*); +void sched(void); +void schedinit(void); +long seconds(void); +Seg *seg(Proc*, ulong); +int segaddr(Seg*, ulong, ulong); +int setlabel(Label*); +void setvmevec(int, void (*)(int)); +char* skipslash(char*); +void sleep(Rendez*, int(*)(void*), void*); +int splhi(void); +int spllo(void); +void splx(int); +Devgen streamgen; +void streamclose(Chan*); +void streaminit(void); +long streamread(Chan*, void*, long); +long streamwrite(Chan*, void*, long); +Stream* streamnew(Chan*, Qinfo*); +void streamopen(Chan*, Qinfo*); +int streamparse(char*, Block*); +long stringread(Chan*, void*, long, char*); +long syscall(Ureg*); +void tlbinit(void); +void touser(void); +void tsleep(Rendez*, int (*)(void*), void*, int); +void twakeme(Alarm*); +void unlock(Lock*); +void usepage(Page*, int); +void userinit(void); +void validaddr(ulong, ulong, int); +void vecinit(void); +void vector80(void); +void* vmemchr(void*, int, int); +void wakeme(Alarm*); +void wakeup(Rendez*); +void wbflush(void); + +#define waserror() setlabel(&u->errlab[u->nerrlab++]) +#define poperror() u->nerrlab-- diff --git a/power/io.h b/power/io.h new file mode 100644 index 0000000000000000000000000000000000000000..fc6fd02aaad8ada84e798bd600d0eb6e68f6cb21 --- /dev/null +++ b/power/io.h @@ -0,0 +1,94 @@ +#define UNCACHED 0xA0000000 +#define IO2(t,x) ((t *)(UNCACHED|0x17000000|(x))) +#define VMEA24SUP(t, x) ((t *)(UNCACHED|0x13000000|(x))) +#define SYNCBUS(t,x) ((t *)(UNCACHED|0x1E000000|(x))) +#define SBSEM SYNCBUS(ulong, 0) +#define SBSEMTOP SYNCBUS(ulong, 0x400000) + +#define LED ((char*)0xBF200001) + +typedef struct SBCC SBCC; +typedef struct Timer Timer; +typedef struct Duart Duart; + +struct SBCC +{ + ulong level[14]; /* cpu interrupt level for cpu->cpu ints */ + ulong junk0[2]; + ulong status[14]; /* status from other cpu */ + ulong junk1[2]; + ulong elevel; /* cpu interrupt level for vme->cpu ints */ + ulong junk2[7]; + ulong flevel; /* cpu interrupt level for vme->cpu ints */ + ulong junk3[3]; + ulong overrun; + ulong junk4[3]; + ulong id; /* id of this cpu */ + ulong eintenable; + ulong eintpending; + ulong fintenable; + ulong fintpending; + ulong idintenable; + ulong idintpending; + ulong junk5[8]; + ulong intxmit; +}; + +#define SBCCREG SYNCBUS(SBCC, 0x400000) + +#define TIMERREG SYNCBUS(Timer, 0x1600000) +#define CLRTIM0 SYNCBUS(uchar, 0x1100000) +#define CLRTIM1 SYNCBUS(uchar, 0x1180000) + +#define DUARTREG SYNCBUS(Duart, 0x1A00000) + +#define LANCERAM IO2(uchar, 0xE00000) +#define LANCEEND IO2(uchar, 0xF00000) +#define LANCERDP IO2(ushort, 0xFC0002) +#define LANCERAP IO2(ushort, 0xFC000a) +#define LANCEID IO2(ushort, 0xFF0002) + +typedef struct MODE MODE; +typedef struct INTVEC INTVEC; + +struct MODE { + uchar masterslave; /* master/slave addresses for the IO2 */ + uchar resetforce; + uchar checkbits; + uchar promenet; +}; + +#define MODEREG IO2(MODE, 0xF40000) + +#define MASTER 0x0 +#define SLAVE 0x4 + +struct INTVEC { + struct { + ulong vec; + ulong fill2; + } i[8]; +}; + +#define INTVECREG IO2(INTVEC, 0xF60000) +#define INTPENDREG IO2(uchar, 0xF20000) /* same as LED */ +#define IO2CLRMASK IO2(uchar, 0xFE0000) +#define IO2SETMASK IO2(uchar, 0xFE8000) +#define IO2MASK IO2(ushort, 0xFE8000) +#define MPBERR0 IO2(ulong, 0xF48000) +#define MPBERR1 IO2(ulong, 0xF4C000) +#define SBEADDR ((ulong *)(UNCACHED|0x1f080000)) + +/* + * hsvme datakit board + */ +struct hsvme { + ushort version; + ushort pad0x02; + ushort vector; + ushort pad0x06; + ushort csr; + ushort pad0x0A; + ushort data; +}; +#define HSVME VMEA24SUP(struct hsvme, 0xF90000) diff --git a/power/l.s b/power/l.s new file mode 100644 index 0000000000000000000000000000000000000000..2cb98d5351eb1aaba023099dde42c159b3e55385 --- /dev/null +++ b/power/l.s @@ -0,0 +1,454 @@ +#include "mem.h" + +#define SP R29 + +#define PROM (KSEG1+0x1FC00000) +#define NOOP NOR R0,R0 +#define WAIT NOOP; NOOP + +/* + * Boot first processor + */ +TEXT start(SB), $-4 + + MOVW $setR30(SB), R30 + MOVW $(CU1|INTR5|INTR4|INTR3|INTR2|INTR1|SW1|SW0), R1 + MOVW R1, M(STATUS) + WAIT + + MOVW $(0x1C<<7), R1 + MOVW R1, FCR31 /* permit only inexact and underflow */ + NOOP + MOVD $0.5, F26 + SUBD F26, F26, F24 + ADDD F26, F26, F28 + ADDD F28, F28, F30 + + MOVD F24, F0 + MOVD F24, F2 + MOVD F24, F4 + MOVD F24, F6 + MOVD F24, F8 + MOVD F24, F10 + MOVD F24, F12 + MOVD F24, F14 + MOVD F24, F16 + MOVD F24, F18 + MOVD F24, F20 + MOVD F24, F22 + + MOVW $MACHADDR, R(MACH) + ADDU $(BY2PG-4), R(MACH), SP + MOVW $0, R(USER) + MOVW R0, 0(R(MACH)) + + MOVW $edata(SB), R1 + MOVW $end(SB), R2 + +clrbss: + MOVB $0, (R1) + ADDU $1, R1 + BNE R1, R2, clrbss + + JAL main(SB) + JMP (R0) + +/* + * Take first processor into user mode + */ + +TEXT touser(SB), $-4 + MOVW M(STATUS), R1 + OR $(KUP|IEP), R1 + MOVW R1, M(STATUS) + NOOP + MOVW $(USTKTOP-20), SP + MOVW $(UTZERO+32), R26 /* header appears in text */ + RFE (R26) + +/* + * Bring subsequent processors on line + */ +TEXT newstart(SB), $0 + + MOVW $setR30(SB), R30 + MOVW $(INTR5|INTR4|INTR3|INTR2|INTR1|SW1|SW0), R1 + MOVW R1, M(STATUS) + NOOP + MOVW $MACHADDR, R(MACH) + MOVB (MPID+3), R1 + AND $7, R1 + SLL $PGSHIFT, R1, R2 + ADDU R2, R(MACH) + ADDU $(BY2PG-4), R(MACH), SP + MOVW $0, R(USER) + MOVW R1, 0(R(MACH)) + JAL online(SB) + JMP (R0) + +TEXT firmware(SB), $0 + + MOVW $(PROM+0x18), R1 /**/ +/* MOVW $(PROM+0x00), R1 /**/ + JMP (R1) + +TEXT splhi(SB), $0 + + MOVW M(STATUS), R1 + AND $~IEC, R1, R2 + MOVW R2, M(STATUS) + NOOP + RET + +TEXT spllo(SB), $0 + + MOVW M(STATUS), R1 + OR $IEC, R1, R2 + MOVW R2, M(STATUS) + NOOP + RET + +TEXT splx(SB), $0 + + MOVW 0(FP), R1 + MOVW M(STATUS), R2 + AND $IEC, R1 + AND $~IEC, R2 + OR R2, R1 + MOVW R1, M(STATUS) + NOOP + RET + +TEXT wbflush(SB), $-4 + + MOVW $WBFLUSH, R1 + MOVW 0(R1), R1 + RET + +TEXT setlabel(SB), $0 + + MOVW 0(FP), R2 + MOVW $0, R1 + MOVW R31, 0(R2) + MOVW R29, 4(R2) + RET + +TEXT gotolabel(SB), $0 + + MOVW 0(FP), R2 + MOVW $1, R1 + MOVW 0(R2), R31 + MOVW 4(R2), R29 + RET + +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 + TLBP + NOOP + MOVW M(INDEX), R4 + BGEZ R4, index + TLBWR + NOOP + JAL splx(SB) + RET +index: + TLBWI + NOOP + JAL splx(SB) + RET + +TEXT puttlbx(SB), $0 + + MOVW 0(FP), R4 + MOVW 4(FP), R2 + MOVW 8(FP), R3 + SLL $8, R4 + MOVW R2, M(TLBVIRT) + MOVW R3, M(TLBPHYS) + MOVW R4, M(INDEX) + NOOP + TLBWI + NOOP + RET + +TEXT tlbp(SB), $0 + TLBP + NOOP + MOVW M(INDEX), R1 + RET + +TEXT tlbvirt(SB), $0 + TLBP + NOOP + MOVW M(TLBVIRT), R1 + RET + + +TEXT gettlb(SB), $0 + + MOVW 0(FP), R3 + MOVW 4(FP), R4 + SLL $8, R3 + MOVW R3, M(INDEX) + NOOP + TLBR + NOOP + MOVW M(TLBVIRT), R1 + MOVW M(TLBPHYS), R2 + NOOP + MOVW R1, 0(R4) + MOVW R2, 4(R4) + RET + +TEXT gettlbvirt(SB), $0 + + MOVW 0(FP), R3 + SLL $8, R3 + MOVW R3, M(INDEX) + NOOP + TLBR + NOOP + MOVW M(TLBVIRT), R1 + NOOP + RET + +TEXT vector80(SB), $-4 + + MOVW $exception(SB), R26 + JMP (R26) + +TEXT exception(SB), $-4 + + MOVW M(STATUS), R26 + AND $KUP, R26 + BEQ R26, waskernel + +wasuser: + MOVW SP, R26 + /* + * set kernel sp: ureg - ureg* - pc + * done in 2 steps because R30 is not set + * and the loader will make a literal + */ + MOVW $((UREGADDR-2*BY2WD) & 0xffff0000), SP + OR $((UREGADDR-2*BY2WD) & 0xffff), SP + MOVW R26, 0x10(SP) /* user SP */ + MOVW R31, 0x28(SP) + MOVW R30, 0x2C(SP) + MOVW M(CAUSE), R26 + MOVW R(MACH), 0x3C(SP) + MOVW R(USER), 0x40(SP) + AND $(0xF<<2), R26 + SUB $(CSYS<<2), R26 + + JAL saveregs(SB) + + MOVW $setR30(SB), R30 + SUBU $(UREGADDR-2*BY2WD-USERADDR), SP, R(USER) + MOVW $MPID, R1 + MOVB 3(R1), R1 + MOVW $MACHADDR, R(MACH) /* locn of mach 0 */ + AND $7, R1 + SLL $PGSHIFT, R1 + ADDU R1, R(MACH) /* add offset for mach # */ + + BNE R26, notsys + + JAL syscall(SB) + + MOVW 0x28(SP), R31 + MOVW 0x08(SP), R26 + MOVW 0x2C(SP), R30 + MOVW R26, M(STATUS) + NOOP + MOVW 0x0C(SP), R26 /* old pc */ + MOVW 0x10(SP), SP + RFE (R26) + +notsys: + JAL trap(SB) + +restore: + JAL restregs(SB) + MOVW 0x28(SP), R31 + MOVW 0x2C(SP), R30 + MOVW 0x3C(SP), R(MACH) + MOVW 0x40(SP), R(USER) + MOVW 0x10(SP), SP + RFE (R26) + +waskernel: + MOVW $1, R26 /* not sys call */ + MOVW SP, -0x90(SP) /* drop this if possible */ + SUB $0xA0, SP + MOVW R31, 0x28(SP) + JAL saveregs(SB) + JAL trap(SB) + JAL restregs(SB) + MOVW 0x28(SP), R31 + ADD $0xA0, SP + RFE (R26) + +TEXT saveregs(SB), $-4 + MOVW R1, 0x9C(SP) + MOVW R2, 0x98(SP) + ADDU $8, SP, R1 + MOVW R1, 0x04(SP) /* arg to base of regs */ + MOVW M(STATUS), R1 + MOVW M(EPC), R2 + MOVW R1, 0x08(SP) + MOVW R2, 0x0C(SP) + + BEQ R26, return /* sys call, don't save */ + + MOVW M(CAUSE), R1 + MOVW M(BADVADDR), R2 + MOVW R1, 0x14(SP) + MOVW M(TLBVIRT), R1 + MOVW R2, 0x18(SP) + MOVW R1, 0x1C(SP) + MOVW HI, R1 + MOVW LO, R2 + MOVW R1, 0x20(SP) + MOVW R2, 0x24(SP) + /* LINK,SB,SP missing */ + MOVW R28, 0x30(SP) + /* R27, R26 not saved */ + /* R25, R24 missing */ + MOVW R23, 0x44(SP) + MOVW R22, 0x48(SP) + MOVW R21, 0x4C(SP) + MOVW R20, 0x50(SP) + MOVW R19, 0x54(SP) + MOVW R18, 0x58(SP) + MOVW R17, 0x5C(SP) + MOVW R16, 0x60(SP) + MOVW R15, 0x64(SP) + MOVW R14, 0x68(SP) + MOVW R13, 0x6C(SP) + MOVW R12, 0x70(SP) + MOVW R11, 0x74(SP) + MOVW R10, 0x78(SP) + MOVW R9, 0x7C(SP) + MOVW R8, 0x80(SP) + MOVW R7, 0x84(SP) + MOVW R6, 0x88(SP) + MOVW R5, 0x8C(SP) + MOVW R4, 0x90(SP) + MOVW R3, 0x94(SP) +return: + RET + +TEXT restregs(SB), $-4 + /* LINK,SB,SP missing */ + MOVW 0x30(SP), R28 + /* R27, R26 not saved */ + /* R25, R24 missing */ + MOVW 0x44(SP), R23 + MOVW 0x48(SP), R22 + MOVW 0x4C(SP), R21 + MOVW 0x50(SP), R20 + MOVW 0x54(SP), R19 + MOVW 0x58(SP), R18 + MOVW 0x5C(SP), R17 + MOVW 0x60(SP), R16 + MOVW 0x64(SP), R15 + MOVW 0x68(SP), R14 + MOVW 0x6C(SP), R13 + MOVW 0x70(SP), R12 + MOVW 0x74(SP), R11 + MOVW 0x78(SP), R10 + MOVW 0x7C(SP), R9 + MOVW 0x80(SP), R8 + MOVW 0x84(SP), R7 + MOVW 0x88(SP), R6 + MOVW 0x8C(SP), R5 + MOVW 0x90(SP), R4 + MOVW 0x94(SP), R3 + MOVW 0x24(SP), R2 + MOVW 0x20(SP), R1 + MOVW R2, LO + MOVW R1, HI + MOVW 0x08(SP), R1 + MOVW 0x98(SP), R2 + MOVW R1, M(STATUS) + NOOP + MOVW 0x9C(SP), R1 + MOVW 0x0C(SP), R26 /* old pc */ + RET + +TEXT rfnote(SB), $0 + MOVW 0(FP), R26 /* 1st arg is &uregpointer */ + SUBU $(BY2WD), R26, SP /* pc hole */ + BNE R26, restore + + +TEXT clrfpintr(SB), $0 + MOVW FCR31, R1 + MOVW R1, R2 + AND $~(0x3F<<12), R2 + MOVW R2, FCR31 + RET + +TEXT savefpregs(SB), $0 + MOVW M(STATUS), R3 + MOVW 0(FP), R1 + MOVW FCR31, R2 + + MOVD F0, 0x00(R1) + MOVD F2, 0x08(R1) + MOVD F4, 0x10(R1) + MOVD F6, 0x18(R1) + MOVD F8, 0x20(R1) + MOVD F10, 0x28(R1) + MOVD F12, 0x30(R1) + MOVD F14, 0x38(R1) + MOVD F16, 0x40(R1) + MOVD F18, 0x48(R1) + MOVD F20, 0x50(R1) + MOVD F22, 0x58(R1) + MOVD F24, 0x60(R1) + MOVD F26, 0x68(R1) + MOVD F28, 0x70(R1) + MOVD F30, 0x78(R1) + + MOVW R2, 0x80(R1) + AND $~CU1, R3 + MOVW R3, M(STATUS) + RET + +TEXT restfpregs(SB), $0 + MOVW M(STATUS), R3 + MOVW 0(FP), R1 + OR $CU1, R3 + MOVW R3, M(STATUS) + MOVW 0x80(R1), R2 + + MOVD 0x00(R1), F0 + MOVD 0x08(R1), F2 + MOVD 0x10(R1), F4 + MOVD 0x18(R1), F6 + MOVD 0x20(R1), F8 + MOVD 0x28(R1), F10 + MOVD 0x30(R1), F12 + MOVD 0x38(R1), F14 + MOVD 0x40(R1), F16 + MOVD 0x48(R1), F18 + MOVD 0x50(R1), F20 + MOVD 0x58(R1), F22 + MOVD 0x60(R1), F24 + MOVD 0x68(R1), F26 + MOVD 0x70(R1), F28 + MOVD 0x78(R1), F30 + + MOVW R2, FCR31 + AND $~CU1, R3 + MOVW R3, M(STATUS) + RET diff --git a/power/lock.c b/power/lock.c new file mode 100644 index 0000000000000000000000000000000000000000..21f8fc23ea25a512c5d8065533bc429a0f960eab --- /dev/null +++ b/power/lock.c @@ -0,0 +1,157 @@ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" + +/* + * The hardware semaphores are strange. 64 per page, replicated 16 times + * per page, 1024 pages of them. Only the low bit is meaningful. + * Reading an unset semaphore sets the semaphore and returns the old value. + * Writing a semaphore sets the value, so writing 0 resets (clears) the semaphore. + */ + +#define SEMPERPG 64 /* hardware semaphores per page */ +#define NONSEMPERPG (WD2PG-64) /* words of non-semaphore per page */ + +struct +{ + Lock lock; /* lock to allocate */ + ulong *nextsem; /* next one to allocate */ + int nsem; /* at SEMPERPG, jump to next page */ +}semalloc; + +void +lockinit(void) +{ + semalloc.lock.sbsem = SBSEM; + semalloc.nextsem = SBSEM+1; + semalloc.nsem = 1; + unlock(&semalloc.lock); +} + +/* + * If l->sbsem is zero, allocate a hardware semaphore first. + * There is no way to free a semaphore. + */ +void +lock(Lock *l) +{ +int addr; + int i; + ulong *sbsem; + + sbsem = l->sbsem; + if(sbsem == 0){ + lock(&semalloc.lock); + if(semalloc.nsem == SEMPERPG){ + semalloc.nsem = 0; + semalloc.nextsem += NONSEMPERPG; + if(semalloc.nextsem == SBSEMTOP) + panic("sem"); + } + l->sbsem = semalloc.nextsem; + semalloc.nextsem++; + semalloc.nsem++; + unlock(&semalloc.lock); + unlock(l); /* put sem in known state */ + sbsem = l->sbsem; + } + /* + * Try the fast grab first + */ + if((*sbsem&1) == 0){ + l->pc = ((ulong*)&addr)[-7]; + return; + } + for(i=0; i<10000000; i++) + if((*sbsem&1) == 0){ + l->pc = ((ulong*)&addr)[-7]; + return; + } + *sbsem = 0; + print("lock loop %lux pc %lux held by pc %lux\n", l, ((ulong*)&addr)[-7], l->pc); +} + +int +canlock(Lock *l) +{ + ulong *sbsem; + + sbsem = l->sbsem; + if(sbsem == 0){ + lock(&semalloc.lock); + if(semalloc.nsem == SEMPERPG){ + semalloc.nsem = 0; + semalloc.nextsem += NONSEMPERPG; + if(semalloc.nextsem == SBSEMTOP) + panic("sem"); + } + l->sbsem = semalloc.nextsem; + semalloc.nextsem++; + semalloc.nsem++; + unlock(&semalloc.lock); + unlock(l); /* put sem in known state */ + sbsem = l->sbsem; + } + if(*sbsem & 1) + return 0; + return 1; +} + +void +unlock(Lock *l) +{ + l->pc = 0; + *l->sbsem = 0; +} + +int +canqlock(QLock *q) +{ + return canlock(&q->use); +} + +void +qlock(QLock *q) +{ + Proc *p; + + if(canlock(&q->use)) + return; + lock(&q->queue); + if(canlock(&q->use)){ + unlock(&q->queue); + return; + } + p = q->tail; + if(p == 0) + q->head = u->p; + else + p->qnext = u->p; + q->tail = u->p; + u->p->qnext = 0; + u->p->state = Queueing; + unlock(&q->queue); + sched(); +} + +void +qunlock(QLock *q) +{ + Proc *p; + + lock(&q->queue); + if(q->head){ + p = q->head; + q->head = p->qnext; + if(q->head == 0) + q->tail = 0; + unlock(&q->queue); + ready(p); + }else{ + unlock(&q->use); + unlock(&q->queue); + } +} diff --git a/power/main.c b/power/main.c new file mode 100644 index 0000000000000000000000000000000000000000..8ee8343bd2c7dc197074d06e34e44054828febe9 --- /dev/null +++ b/power/main.c @@ -0,0 +1,390 @@ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" +#include "ureg.h" +#include "init.h" + +void +main(void) +{ + active.exiting = 0; + active.machs = 1; + machinit(); + confinit(); + lockinit(); + printinit(); + tlbinit(); + vecinit(); + procinit0(); + pgrpinit(); + chaninit(); + clockinit(); + alarminit(); + io2init(); + chandevreset(); + streaminit(); + pageinit(); + userinit(); + launchinit(); + schedinit(); +} + +void +machinit(void) +{ + int n; + + n = m->machno; + memset(m, 0, sizeof(Mach)); + m->machno = n; + m->mmask = 1<machno; +} + +void +tlbinit(void) +{ + int i; + + for(i=0; iresetforce = (1<<1); + for(i=0; i<1000000; i++) + ; + MODEREG->resetforce = 0; + MODEREG->masterslave = (SLAVE<<4) | MASTER; + + /* + * all VME interrupts to the error routine + */ + for(i=0; i<256; i++) + setvmevec(i, novme); + + /* + * tell IO2 to sent all interrupts to CPU 0's SBCC + */ + for(i=0; i<8; i++) + INTVECREG->i[i].vec = 0<<8; + + /* + * Tell CPU 0's SBCC to map all interrupts from the IO2 to MIPS level 5 + * + * Since there are 6 MIPS hardware interrupts and the SBCC can generate + * only 5, one hardware interrupt can't be generated by the SBCC. SBCC + * interrupt 4 maps to MIPS interrupt 5, SBCC interrupt 0 maps to MIPS + * interrupt 0. I don't know which interrupt is missing. -- presotto + */ + SBCCREG->flevel = 0x10; + + /* + * Tell CPU 0's SBCC to enable all interrupts from the IO2. + * + * The SBCC 16 bit registers are read/written as ulong, but only + * bits 23-16 and 7-0 are meaningful. + */ + SBCCREG->fintenable |= 0xff; /* allow all interrupts on the IO2 */ + SBCCREG->idintenable |= 0x800000; /* allow interrupts from the IO2 */ + + /* + * enable all interrupts on the IO2 + */ + *IO2SETMASK = 0xff; +} + +void +launchinit(void) +{ + int i; + + for(i=1; iproc = u->p; + u->p->state = Running; + u->p->mach = m; + spllo(); + chandevinit(); + + u->slash = (*devtab[0].attach)(0); + u->dot = clone(u->slash, 0); + + touser(); +} + +FPsave initfp; + +void +userinit(void) +{ + Proc *p; + Seg *s; + User *up; + + p = newproc(); + p->pgrp = newpgrp(); + strcpy(p->text, "*init*"); + strcpy(p->pgrp->user, "bootes"); + savefpregs(&initfp); + p->fpstate = FPinit; + + /* + * Kernel Stack + */ + p->sched.pc = (ulong)init0; + p->sched.sp = USERADDR+BY2PG-20; + p->upage = newpage(0, 0, USERADDR|(p->pid&0xFFFF)); + + /* + * User + */ + up = (User*)(p->upage->pa|KZERO); + up->p = p; + + /* + * User Stack + */ + s = &p->seg[SSEG]; + s->proc = p; + s->o = neworig(USTKTOP-BY2PG, 1, OWRPERM, 0); + s->minva = USTKTOP-BY2PG; + s->maxva = USTKTOP; + + /* + * Text + */ + s = &p->seg[TSEG]; + s->proc = p; + s->o = neworig(UTZERO, 1, 0, 0); + s->o->pte[0].page = newpage(0, 0, UTZERO); + memcpy((ulong*)(s->o->pte[0].page->pa|KZERO), initcode, sizeof initcode); + s->minva = 0x1000; + s->maxva = 0x2000; + + ready(p); +} + +void +lights(int v) +{ + + *LED = ~v; +} + +typedef struct Beef Beef; +struct Beef +{ + long deadbeef; + long sum; + long cpuid; + long virid; + long erno; + void (*launch)(void); + void (*rend)(void); + long junk1[4]; + long isize; + long dsize; + long nonbss; + long junk2[18]; +}; + +void +launch(int n) +{ + Beef *p; + long i; + + p = (Beef*) 0xb0000500 + n; + p->launch = newstart; + p->sum -= (long)newstart; + for(i=0; i<3000000; i++) + if(p->launch == 0) + break; +} + +void +online(void) +{ + + machinit(); + lock(&active); + active.machs |= 1<machno; + unlock(&active); + tlbinit(); + clockinit(); + schedinit(); +} + +void +exit(void) +{ + int i; + + u = 0; + lock(&active); + active.machs &= ~(1<machno); + active.exiting = 1; + unlock(&active); + spllo(); + print("cpu %d exiting\n", m->machno); + while(active.machs || consactive()) + for(i=0; i<1000; i++) + ; + splhi(); + for(i=0; i<2000000; i++) + ; + duartreset(); + firmware(); +} + +/* + * Insert new into list after where + */ +void +insert(List **head, List *where, List *new) +{ + if(where == 0){ + new->next = *head; + *head = new; + }else{ + new->next = where->next; + where->next = new; + } + +} + +/* + * Insert new into list at end + */ +void +append(List **head, List *new) +{ + List *where; + + where = *head; + if(where == 0) + *head = new; + else{ + while(where->next) + where = where->next; + where->next = new; + } + new->next = 0; +} + +/* + * Delete old from list + */ +void +delete0(List **head, List *old) +{ + List *l; + + l = *head; + if(l == old){ + *head = old->next; + return; + } + while(l->next != old) + l = l->next; + l->next = old->next; +} + +/* + * Delete old from list. where->next is known to be old. + */ +void +delete(List **head, List *where, List *old) +{ + if(where == 0){ + *head = old->next; + return; + } + where->next = old->next; +} + +Conf conf; + +void +confinit(void) +{ + long x, i, j, *l; + + conf.nmach = 4; + if(conf.nmach > MAXMACH) + panic("confinit"); + conf.nproc = 193; + conf.npgrp = 100; + + x = 0x12345678; + for(i=4; i<64; i+=4){ + l = (long*)(KSEG1|(i*1024L*1024L)); + *l = x; + wbflush(); + *(ulong*)KSEG1 = *(ulong*)KSEG1; /* clear latches */ + if(*l != x) + break; + x += 0x3141526; + } + conf.npage = i*1024/4; + + conf.npte = 20000; + conf.nmod = 500; + conf.nalarm = 1000; + conf.norig = 500; + conf.nchan = 500; + conf.nenv = 200; + conf.nenvchar = 10000; + conf.npgenv = 200; + conf.nmtab = 100; + conf.nmount = 500; + conf.nmntdev = 30; + conf.nmntbuf = 60; + conf.nmnthdr = 60; + conf.nstream = 512; + conf.nqueue = 5 * conf.nstream; + conf.nblock = 16 * conf.nstream; + conf.nsrv = 32; +} diff --git a/power/mem.h b/power/mem.h new file mode 100644 index 0000000000000000000000000000000000000000..7ecde107569842755d9f6ba210ffe7f09cfb13aa --- /dev/null +++ b/power/mem.h @@ -0,0 +1,127 @@ +/* + * Memory and machine-specific definitions. Used in C and assembler. + */ + +/* + * Sizes + */ + +#define BI2BY 8 /* bits per byte */ +#define BI2WD 32 /* bits per word */ +#define BY2WD 4 /* bytes per word */ +#define BY2PG 4096 /* bytes per page */ +#define WD2PG (BY2PG/BY2WD) /* words per page */ +#define PGSHIFT 12 /* log(BY2PG) */ +#define MS2HZ 50 /* millisec per clock tick */ + +#define MAXMACH 4 /* max # cpus system can run */ + +/* + * CP0 registers + */ + +#define INDEX 0 +#define RANDOM 1 +#define TLBPHYS 2 +#define CONTEXT 4 +#define BADVADDR 8 +#define TLBVIRT 10 +#define STATUS 12 +#define CAUSE 13 +#define EPC 14 +#define PRID 15 + +/* + * M(STATUS) bits + */ +#define IEC 0x00000001 +#define KUC 0x00000002 +#define IEP 0x00000004 +#define KUP 0x00000008 +#define INTMASK 0x0000ff00 +#define SW0 0x00000100 +#define SW1 0x00000200 +#define INTR0 0x00000400 +#define INTR1 0x00000800 +#define INTR2 0x00001000 +#define INTR3 0x00002000 +#define INTR4 0x00004000 +#define INTR5 0x00008000 +#define ISC 0x00010000 +#define SWC 0x00020000 +#define CU1 0x20000000 + +/* + * Traps + */ + +#define UTLBMISS (KSEG0+0x00) +#define EXCEPTION (KSEG0+0x80) + +/* + * Magic registers + */ + +#define MACH 25 /* R25 is m-> */ +#define USER 24 /* R24 is u-> */ +#define MPID 0xBF000000 /* long; low 3 bits identify mp bus slot */ +#define WBFLUSH 0xBC000000 /* D-CACHE data; used for write buffer flush */ + +/* + * Fundamental addresses + */ + +#define MACHADDR 0x80014000 +#define USERADDR 0xC0000000 +#define UREGADDR (USERADDR+BY2PG-4-0xA0) +/* + * MMU + */ + +#define KUSEG 0x00000000 +#define KSEG0 0x80000000 +#define KSEG1 0xA0000000 +#define KSEG2 0xC0000000 +#define KSEGM 0xE0000000 /* mask to check which seg */ + +#define PTEGLOBL (1<<8) +#define PTEVALID (1<<9) +#define PTEWRITE (1<<10) +#define PTEPID(n) ((n)<<6) + +#define NTLBPID 64 /* number of pids */ +#define NTLB 64 /* number of entries */ +#define TLBROFF 8 /* offset of first randomly indexed entry */ + +/* + * Address spaces + */ + +#define UZERO KUSEG /* base of user address space */ +#define UTZERO (UZERO+BY2PG) /* first address in user text */ +#define USTKTOP KZERO /* byte just beyond user stack */ +#define TSTKTOP (USERADDR+100*BY2PG) /* top of temporary stack */ +#define KZERO KSEG0 /* base of kernel address space */ +#define KTZERO (KSEG0+0x20000) /* first address in kernel text */ + +/* + * Exception codes + */ +#define CINT 0 /* external interrupt */ +#define CTLBM 1 /* TLB modification */ +#define CTLBL 2 /* TLB miss (load or fetch) */ +#define CTLBS 3 /* TLB miss (store) */ +#define CADREL 4 /* address error (load or fetch) */ +#define CADRES 5 /* address error (store) */ +#define CBUSI 6 /* bus error (fetch) */ +#define CBUSD 7 /* bus error (data load or store) */ +#define CSYS 8 /* system call */ +#define CBRK 9 /* breakpoint */ +#define CRES 10 /* reserved instruction */ +#define CCPU 11 /* coprocessor unusable */ +#define COVF 12 /* arithmetic overflow */ +#define CUNK13 13 /* undefined 13 */ +#define CUNK14 14 /* undefined 14 */ +#define CUNK15 15 /* undefined 15 */ + +#define NSEG 5 diff --git a/power/mmu.c b/power/mmu.c new file mode 100644 index 0000000000000000000000000000000000000000..fc9a724677e05f0866d40b99cdec3cfa4238f083 --- /dev/null +++ b/power/mmu.c @@ -0,0 +1,103 @@ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" + +/* + * Called splhi, not in Running state + */ +void +mapstack(Proc *p) +{ + short tp; + ulong tlbvirt, tlbphys; + + tp = p->pidonmach[m->machno]; + if(tp == 0){ + tp = newtlbpid(p); + p->pidonmach[m->machno] = tp; + } +/* if(p->upage->va != (USERADDR|(p->pid&0xFFFF))) + panic("mapstack %d 0x%lux 0x%lux", p->pid, p->upage->pa, p->upage->va); +*/ + /* don't set m->pidhere[*tp] because we're only writing entry 0 */ + tlbvirt = USERADDR | PTEPID(tp); + tlbphys = p->upage->pa | PTEWRITE | PTEVALID | PTEGLOBL; + puttlbx(0, tlbvirt, tlbphys); + u = (User*)USERADDR; +} + +/* + * Process must be non-interruptible + */ +int +newtlbpid(Proc *p) +{ + int i; + Proc *sp; + + i = m->lastpid+1; + if(i >= NTLBPID) + i = 1; + sp = m->pidproc[i]; + if(sp){ + sp->pidonmach[m->machno] = 0; + purgetlb(i); + } + m->pidproc[i] = p; + m->lastpid = i; + return i; +} + +void +putmmu(ulong tlbvirt, ulong tlbphys) +{ + short tp; + Proc *p; + + splhi(); + p = u->p; +/* if(p->state != Running) + panic("putmmu state %lux %lux %s\n", u, p, statename[p->state]); +*/ + p->state = MMUing; + tp = p->pidonmach[m->machno]; + if(tp == 0){ + tp = newtlbpid(p); + p->pidonmach[m->machno] = tp; + } + tlbvirt |= PTEPID(tp); + puttlb(tlbvirt, tlbphys); + m->pidhere[tp] = 1; + p->state = Running; + spllo(); +} + +void +purgetlb(int pid) +{ + int i, rpid; + + if(m->pidhere[pid] == 0) + return; + memset(m->pidhere, 0, sizeof m->pidhere); + for(i=TLBROFF; i>6) & 0x3F; + if(rpid == pid) + puttlbx(i, KZERO | PTEPID(i), 0); + else + m->pidhere[rpid] = 1; + } +} + +void +flushmmu(void) +{ + splhi(); + /* easiest is to forget what pid we had.... */ + memset(u->p->pidonmach, 0, sizeof u->p->pidonmach); + /* ....then get a new one by trying to map our stack */ + mapstack(u->p); + spllo(); +} diff --git a/power/trap.c b/power/trap.c new file mode 100644 index 0000000000000000000000000000000000000000..01c9a39dc56173e128bd243ba2bdad0d8366d884 --- /dev/null +++ b/power/trap.c @@ -0,0 +1,499 @@ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "ureg.h" +#include "io.h" + +/* + * vme interrupt routines + */ +void (*vmevec[256])(int); + +void notify(Ureg*); +void noted(Ureg**); +void rfnote(Ureg**); + +#define LSYS 0x01 +#define LUSER 0x02 +/* + * CAUSE register + */ + +#define EXCCODE(c) ((c>>2)&0x0F) +#define FPEXC 16 + +char *excname[] = +{ + "external interrupt", + "TLB modification", + "TLB miss (load or fetch)", + "TLB miss (store)", + "address error (load or fetch)", + "address error (store)", + "bus error (fetch)", + "bus error (data load or store)", + "system call", + "breakpoint", + "reserved instruction", + "coprocessor unusable", + "arithmetic overflow", + "undefined 13", + "undefined 14", + "undefined 15", + /* the following is made up */ + "floating point exception" /* FPEXC */ +}; +char *fpexcname(ulong); + +char *regname[]={ + "STATUS", "PC", + "SP", "CAUSE", + "BADADDR", "TLBVIRT", + "HI", "LO", + "R31", "R30", + "R28", "R27", + "R26", "R25", + "R24", "R23", + "R22", "R21", + "R20", "R19", + "R18", "R17", + "R16", "R15", + "R14", "R13", + "R12", "R11", + "R10", "R9", + "R8", "R7", + "R6", "R5", + "R4", "R3", + "R2", "R1", +}; + +long ticks; + +void +trap(Ureg *ur) +{ + int ecode; + int user; + ulong x; + char buf[ERRLEN]; + + ecode = EXCCODE(ur->cause); + user = ur->status&KUP; + if(u) + u->p->pc = ur->pc; /* BUG */ + switch(ecode){ + case CINT: + m->intrp = 0; + if(u && u->p->state==Running){ + if(u->p->fpstate == FPactive) { + if(ur->cause & INTR3){ /* FP trap */ + x = clrfpintr(); + ecode = FPEXC; + } + savefpregs(&u->fpsave); + u->p->fpstate = FPinactive; + ur->status &= ~CU1; + if(ecode == FPEXC) + goto Default; + } + m->intr = intr; + m->cause = ur->cause; + if(ur->cause & INTR2) + m->intrp = u->p; + sched(); + }else + intr(ur->cause); + break; + + case CTLBM: + case CTLBL: + case CTLBS: + if(u == 0) + panic("fault"); + if(u->p->fpstate == FPactive) { + savefpregs(&u->fpsave); + u->p->fpstate = FPinactive; + ur->status &= ~CU1; + } + spllo(); + x = u->p->insyscall; + u->p->insyscall = 1; + fault(ur, user, ecode); + u->p->insyscall = x; + break; + + case CCPU: + if(u->p->fpstate == FPinit) { + restfpregs(&initfp); + u->p->fpstate = FPactive; + ur->status |= CU1; + break; + } + if(u->p->fpstate == FPinactive) { + restfpregs(&u->fpsave); + u->p->fpstate = FPactive; + ur->status |= CU1; + break; + } + + default: + Default: + /* + * This isn't good enough; can still deadlock because we may hold print's locks + * in this processor. + */ + if(user){ + spllo(); + if(ecode == FPEXC) + sprint(buf, "fp: %s FCR31 %lux", fpexcname(x), x); + else + sprint(buf, "trap: %s", excname[ecode]); + postnote(u->p, 1, buf, NDebug); + }else{ + print("%s %s pc=%lux\n", user? "user": "kernel", excname[ecode], ur->pc); + if(ecode == FPEXC) + print("fp: %s FCR31 %lux\n", fpexcname(x), x); + dumpregs(ur); + if(m->machno == 0) + spllo(); + exit(); + } + } + if(user && u->nnote) + notify(ur); + splhi(); + if(user && u && u->p->fpstate == FPinactive) { + restfpregs(&u->fpsave); + u->p->fpstate = FPactive; + ur->status |= CU1; + } +} + +void +intr(ulong cause) +{ + int i, pend; + long v; + + cause &= INTR5|INTR4|INTR3|INTR2|INTR1; + if(cause & (INTR2|INTR4)){ + clock(cause); + cause &= ~(INTR2|INTR4); + } + if(cause & INTR1){ + duartintr(); + cause &= ~INTR1; + } + if(cause & INTR5){ + + if(!(*MPBERR1 & (1<<8))){ +/* print("MP bus error %lux\n", *MPBERR0); /**/ + *MPBERR0 = 0; + i = *SBEADDR; + } + + /* + * directions from IO2 manual + * 1. clear all IO2 masks + */ + *IO2CLRMASK = 0xff; + + /* + * 2. wait for interrupt in progress + */ + while(!(*INTPENDREG & (1<<5))) + ; + + /* + * 3. read pending interrupts + */ + pend = SBCCREG->fintpending & 0xff; + + /* + * 4. clear pending register + */ + i = SBCCREG->flevel; + + /* + * 5a. process lance, scsi + */ + loop: + if(pend & 1) { + v = INTVECREG->i[0].vec; +/* a botch, bit 12 seems to always be on + if(v & (1<<12)) + print("io2 mp bus error %d\n", 0); + */ + if(!(v & (1<<2))) + lanceintr(); + if(!(v & (1<<1))) + lanceparity(); + if(!(v & (1<<0))) + print("SCSI interrupt\n"); + } + /* + * 5b. process vme + * i bet i can guess your level + */ + pend >>= 1; + for(i=1; pend; i++) { + if(pend & 1) { + v = INTVECREG->i[i].vec; +/* a botch, bit 12 seems to always be on + if(v & (1<<12)) + print("io2 mp bus error %d\n", i); + */ + v &= 0xff; + (*vmevec[v])(v); + } + pend >>= 1; + } + /* + * 6. re-enable interrupts + */ + *IO2SETMASK = 0xff; + cause &= ~INTR5; + } + if(cause) + panic("cause %lux %lux\n", u, cause); +} + +char * +fpexcname(ulong x) +{ + static char *str[]={ + "inexact operation", + "underflow", + "overflow", + "division by zero", + "invalid operation", + "unimplemented operation", + }; + int i; + + x >>= 12; + for(i=0; i<6; i++, x>>=1) + if(x & 1) + return str[i]; + return "no floating point exception"; +} +void +dumpstack(void) +{ + ulong l, v; + extern ulong etext; + + if(u) + for(l=(ulong)&l; lp->text, u->p->pid); + else + print("registers for kernel\n"); + l = &ur->status; + for(i=0; ip->debug); + if(u->nnote==0){ + unlock(&u->p->debug); + return; + } + if(u->note[0].flag!=NUser && (u->notified || u->notify==0)){ + if(u->note[0].flag == NDebug) + pprint("suicide: %s\n", u->note[0].msg); + Die: + unlock(&u->p->debug); + pexit(u->note[0].msg, u->note[0].flag!=NDebug); + } + if(!u->notified){ + if(!u->notify) + goto Die; + sp = ur->sp; + sp -= sizeof(Ureg); + u->ureg = (void*)sp; + memcpy((Ureg*)sp, ur, sizeof(Ureg)); + sp -= ERRLEN; + memcpy((char*)sp, u->note[0].msg, ERRLEN); + sp -= 3*BY2WD; + *(ulong*)(sp+2*BY2WD) = sp+3*BY2WD; /* arg 2 is string */ + *(ulong*)(sp+1*BY2WD) = (ulong)u->ureg; /* arg 1 is ureg* */ + *(ulong*)(sp+0*BY2WD) = 0; /* arg 0 is pc */ + ur->sp = sp; + ur->pc = (ulong)u->notify; + u->notified = 1; + u->nnote--; + memcpy(&u->note[0], &u->note[1], u->nnote*sizeof(Note)); + } + unlock(&u->p->debug); +} + +/* + * Return user to state before notify() + */ +void +noted(Ureg **urp) +{ + lock(&u->p->debug); + u->notified = 0; + memcpy(*urp, u->ureg, sizeof(Ureg)); + unlock(&u->p->debug); + splhi(); + rfnote(urp); +} + + +#undef CHDIR /* BUG */ +#include "/sys/src/libc/mips9sys/sys.h" + +typedef long Syscall(ulong*); +Syscall sysaccess, sysbind, sysbrk_, syschdir, sysclose, syscreate; +Syscall sysdup, syserrstr, sysexec, sysexits, sysfork, sysforkpgrp; +Syscall sysfstat, sysfwstat, sysgetpid, syslasterr, sysmount, sysnoted; +Syscall sysnotify, sysopen, syspipe, sysr1, sysread, sysremove, sysseek; +Syscall syssleep, sysstat, sysuserstr, syswait, syswrite, syswstat; + +Syscall *systab[]={ + [SYSR1] sysr1, + [ACCESS] sysaccess, + [BIND] sysbind, + [CHDIR] syschdir, + [CLOSE] sysclose, + [DUP] sysdup, + [ERRSTR] syserrstr, + [EXEC] sysexec, + [EXITS] sysexits, + [FORK] sysfork, + [FORKPGRP] sysforkpgrp, + [FSTAT] sysfstat, + [LASTERR] syslasterr, + [MOUNT] sysmount, + [OPEN] sysopen, + [READ] sysread, + [SEEK] sysseek, + [SLEEP] syssleep, + [STAT] sysstat, + [WAIT] syswait, + [WRITE] syswrite, + [PIPE] syspipe, + [CREATE] syscreate, + [USERSTR] sysuserstr, + [BRK_] sysbrk_, + [REMOVE] sysremove, + [WSTAT] syswstat, + [FWSTAT] sysfwstat, + [NOTIFY] sysnotify, + [NOTED] sysnoted, +}; + +long +syscall(Ureg *aur) +{ + long ret; + ulong sp; + ulong r1; + Ureg *ur; + + u->p->insyscall = 1; + ur = aur; + /* + * since the system call interface does not + * guarantee anything about registers, + */ + if(u->p->fpstate == FPactive) { + u->p->fpstate = FPinit; /* BUG */ + ur->status &= ~CU1; + } + spllo(); + r1 = ur->r1; + sp = ur->sp; + if(r1 >= sizeof systab/BY2WD) + panic("syscall %d\n", r1); + if(sp & (BY2WD-1)) + panic("syscall odd sp"); + if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-4*BY2WD)) + validaddr(ur->sp, 4*BY2WD, 0); + + u->nerrlab = 0; + ret = -1; + if(!waserror()) + ret = (*systab[r1])((ulong*)(sp+2*BY2WD)); + ur->pc += 4; + u->nerrlab = 0; + splhi(); + if(r1 == NOTED) /* ugly hack */ + noted(&aur); /* doesn't return */ + if(u->nnote){ + ur->r1 = ret; + notify(ur); + } + u->p->insyscall = 0; + return ret; +} + +void +error(Chan *c, int code) +{ + if(c){ + u->error.type = c->type; + u->error.dev = c->dev; + }else{ + u->error.type = 0; + u->error.dev = 0; + } + u->error.code = code; + nexterror(); +} + +void +nexterror(void) +{ + gotolabel(&u->errlab[--u->nerrlab]); +} + +void +novme(int v) +{ + static count = 0; + + print("vme intr 0x%.2x\n", v); + count++; + if(count >= 10) + panic("too many vme intr"); +} + +void +setvmevec(int v, void (*f)(int)) +{ + void (*g)(int); + + v &= 0xff; + g = vmevec[v]; + if(g && g != novme) + print("second setvmevec to 0x%.2x\n", v); + vmevec[v] = f; +} diff --git a/power/u.h b/power/u.h new file mode 100644 index 0000000000000000000000000000000000000000..81dfccf482a2af1e3a96426b21223e1c14af86d6 --- /dev/null +++ b/power/u.h @@ -0,0 +1,15 @@ +typedef unsigned short ushort; +typedef unsigned char uchar; +typedef unsigned long ulong; +typedef long vlong; +typedef union Length Length; + +union Length +{ + char clength[8]; + vlong vlength; + struct{ + long hlength; + long length; + }; +}; diff --git a/power/ureg.h b/power/ureg.h new file mode 100644 index 0000000000000000000000000000000000000000..a2f08891112b4ae508cc60ff168fadbcadfc6bec --- /dev/null +++ b/power/ureg.h @@ -0,0 +1,41 @@ +struct Ureg +{ + ulong status; + ulong pc; + ulong sp; /* r29 */ + ulong cause; + ulong badvaddr; + ulong tlbvirt; + ulong hi; + ulong lo; + ulong r31; + ulong r30; + ulong r28; + ulong r27; /* unused */ + ulong r26; /* unused */ + ulong r25; + ulong r24; + ulong r23; + ulong r22; + ulong r21; + ulong r20; + ulong r19; + ulong r18; + ulong r17; + ulong r16; + ulong r15; + ulong r14; + ulong r13; + ulong r12; + ulong r11; + ulong r10; + ulong r9; + ulong r8; + ulong r7; + ulong r6; + ulong r5; + ulong r4; + ulong r3; + ulong r2; + ulong r1; +};