M bitsy/clock.c => bitsy/clock.c +27 -1
@@ 69,8 69,10 @@ fastticks(uvlong *hz)
}
static void
-clockintr(Ureg*, void*)
+clockintr(Ureg *ureg, void*)
{
+ Clock0link *lp;
+
/* reset previous interrupt */
timerregs->ossr |= 1<<0;
@@ 78,6 80,30 @@ clockintr(Ureg*, void*)
timerregs->osmr[0] = timerregs->oscr + ClockFreq/HZ;
m->ticks++;
+
+ if(m->proc)
+ m->proc->pc = ureg->pc;
+
+ accounttime();
+ if(kproftimer != nil)
+ kproftimer(ureg->pc);
+
+ checkalarms();
+ ilock(&clock0lock);
+ for(lp = clock0link; lp; lp = lp->link)
+ lp->clock();
+ iunlock(&clock0lock);
+
+ if(up == 0 || up->state != Running)
+ return;
+
+ if(anyready())
+ sched();
+
+ if((ureg->psr & PsrMask) == PsrMusr) {
+ (*(ulong*)(USTKTOP-BY2WD)) += TK2MS(1);
+ segclock(ureg->pc);
+ }
}
void
M bitsy/dat.h => bitsy/dat.h +3 -2
@@ 16,7 16,7 @@ typedef struct Uart Uart;
/*
* parameters for sysproc.c
*/
-#define AOUT_MAGIC (I_MAGIC)
+#define AOUT_MAGIC (E_MAGIC)
struct Lock
{
@@ 82,6 82,7 @@ struct PMMU
{
Page *l1page[Nmeg]; /* this's process' level 1 entries */
ulong l1table[Nmeg]; /* ... */
+ Page *mmufree; /* free mmu pages */
};
/*
@@ 167,7 168,7 @@ struct
int ispanic; /* shutdown in response to a panic */
}active;
-#define MACHP(n) ((Mach*)MACHADDR)
+#define MACHP(n) ((Mach *)(MACHADDR+(n)*BY2PG))
extern Mach *m;
#define up (((Mach*)MACHADDR)->externup)
A bitsy/devsac.c => bitsy/devsac.c +530 -0
@@ 0,0 1,530 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "../port/error.h"
+
+enum
+{
+ OPERM = 0x3, /* mask of all permission types in open mode */
+ Nram = 512,
+ CacheSize = 20,
+ OffsetSize = 4, /* size in bytes of an offset */
+};
+
+typedef struct SacPath SacPath;
+typedef struct Sac Sac;
+typedef struct SacHeader SacHeader;
+typedef struct SacDir SacDir;
+typedef struct Cache Cache;
+
+enum {
+ Magic = 0x5acf5,
+};
+
+struct SacDir
+{
+ char name[NAMELEN];
+ char uid[NAMELEN];
+ char gid[NAMELEN];
+ uchar qid[4];
+ uchar mode[4];
+ uchar atime[4];
+ uchar mtime[4];
+ uchar length[8];
+ uchar blocks[8];
+};
+
+struct SacHeader
+{
+ uchar magic[4];
+ uchar length[8];
+ uchar blocksize[4];
+ uchar md5[16];
+};
+
+
+struct Sac
+{
+ SacDir;
+ SacPath *path;
+};
+
+struct SacPath
+{
+ Ref;
+ SacPath *up;
+ long blocks;
+ int entry;
+ int nentry;
+};
+
+struct Cache
+{
+ long block;
+ ulong age;
+ uchar *data;
+};
+
+enum
+{
+ Pexec = 1,
+ Pwrite = 2,
+ Pread = 4,
+ Pother = 1,
+ Pgroup = 8,
+ Powner = 64,
+};
+
+static char *sacfs = "fs.sac";
+static uchar *data;
+static int blocksize;
+static Sac root;
+static Cache cache[CacheSize];
+static ulong cacheage;
+
+static void sacdir(Chan *, SacDir*, char*);
+static ulong getl(void *p);
+static Sac *saccpy(Sac *s);
+static Sac *saclookup(Sac *s, char *name);
+static int sacdirread(Chan *, char *p, long off, long cnt);
+static void loadblock(void *buf, uchar *offset, int blocksize);
+static void sacfree(Sac*);
+
+static void
+sacinit(void)
+{
+ SacHeader *hdr;
+ uchar *p;
+ char *s;
+ int i;
+
+print("sacinit\n");
+ s = getconf("flash");
+ if(s == nil) {
+ print("devsac: no flash file system\n");
+ return;
+ }
+
+ p = (uchar*)strtoul(s, 0, 0);
+ if(p == 0) {
+ print("devsac: bad address for flash file system\n");
+ return;
+ }
+ data = tarlookup(p, sacfs, &i);
+ if(data == 0) {
+ print("devsac: could not find file: %s\n", sacfs);
+ return;
+ }
+ hdr = (SacHeader*)data;
+ if(getl(hdr->magic) != Magic) {
+print("devsac: bad magic\n");
+ return;
+ }
+ blocksize = getl(hdr->blocksize);
+ root.SacDir = *(SacDir*)(data + sizeof(SacHeader));
+ p = malloc(CacheSize*blocksize);
+ if(p == nil)
+ error("allocating cache");
+ for(i=0; i<CacheSize; i++) {
+ cache[i].data = p;
+ p += blocksize;
+ }
+}
+
+static Chan*
+sacattach(char* spec)
+{
+ Chan *c;
+ int dev;
+
+ dev = atoi(spec);
+ if(dev != 0)
+ error("bad specification");
+
+ // check if init found sac file system in memory
+ if(blocksize == 0)
+ error("devsac: bad magic");
+
+ c = devattach('C', spec);
+ c->qid = (Qid){getl(root.qid), 0};
+ c->dev = dev;
+ c->aux = saccpy(&root);
+ return c;
+}
+
+static Chan*
+sacclone(Chan *c, Chan *nc)
+{
+ nc = devclone(c, nc);
+ nc->aux = saccpy(c->aux);
+ return nc;
+}
+
+static int
+sacwalk(Chan *c, char *name)
+{
+ Sac *sac;
+
+//print("walk %s\n", name);
+
+ isdir(c);
+ if(name[0]=='.' && name[1]==0)
+ return 1;
+ if(name[0]=='.' && name[1]=='.' && name[2]==0)
+ return 1;
+ sac = c->aux;
+ sac = saclookup(sac, name);
+ if(sac == nil) {
+ strncpy(up->error, Enonexist, NAMELEN);
+ return 0;
+ }
+ c->aux = sac;
+ c->qid = (Qid){getl(sac->qid), 0};
+ return 1;
+}
+
+static Chan*
+sacopen(Chan *c, int omode)
+{
+ ulong t, mode;
+ Sac *sac;
+ static int access[] = { 0400, 0200, 0600, 0100 };
+
+ sac = c->aux;
+ mode = getl(sac->mode);
+ if(strcmp(up->user, sac->uid) == 0)
+ mode = mode;
+ else if(strcmp(up->user, sac->gid) == 0)
+ mode = mode<<3;
+ else
+ mode = mode<<6;
+
+ t = access[omode&3];
+ if((t & mode) != t)
+ error(Eperm);
+ c->offset = 0;
+ c->mode = openmode(omode);
+ c->flag |= COPEN;
+ return c;
+}
+
+
+static long
+sacread(Chan *c, void *a, long n, vlong voff)
+{
+ Sac *sac;
+ char *buf, *buf2;
+ int nn, cnt, i, j;
+ uchar *blocks;
+ long length;
+ long off = voff;
+
+ buf = a;
+ cnt = n;
+ if(c->qid.path & CHDIR){
+ cnt = (cnt/DIRLEN)*DIRLEN;
+ if(off%DIRLEN)
+ error("i/o error");
+ return sacdirread(c, buf, off, cnt);
+ }
+ sac = c->aux;
+ length = getl(sac->length);
+ if(off >= length)
+ return 0;
+ if(cnt > length-off)
+ cnt = length-off;
+ if(cnt == 0)
+ return 0;
+ n = cnt;
+ blocks = data + getl(sac->blocks);
+ buf2 = malloc(blocksize);
+ while(cnt > 0) {
+ i = off/blocksize;
+ nn = blocksize;
+ if(nn > length-i*blocksize)
+ nn = length-i*blocksize;
+ loadblock(buf2, blocks+i*OffsetSize, nn);
+ j = off-i*blocksize;
+ nn -= j;
+ if(nn > cnt)
+ nn = cnt;
+ memmove(buf, buf2+j, nn);
+ cnt -= nn;
+ off += nn;
+ buf += nn;
+ }
+ free(buf2);
+ return n;
+}
+
+static long
+sacwrite(Chan *, void *, long, vlong)
+{
+ error(Eperm);
+ return 0;
+}
+
+static void
+sacclose(Chan* c)
+{
+ Sac *sac = c->aux;
+ c->aux = nil;
+ sacfree(sac);
+}
+
+
+static void
+sacstat(Chan *c, char *db)
+{
+ sacdir(c, c->aux, db);
+}
+
+static Sac*
+saccpy(Sac *s)
+{
+ Sac *ss;
+
+ ss = malloc(sizeof(Sac));
+ *ss = *s;
+ if(ss->path)
+ incref(ss->path);
+ return ss;
+}
+
+static SacPath *
+sacpathalloc(SacPath *p, long blocks, int entry, int nentry)
+{
+ SacPath *pp = malloc(sizeof(SacPath));
+ pp->ref = 1;
+ pp->blocks = blocks;
+ pp->entry = entry;
+ pp->nentry = nentry;
+ pp->up = p;
+ return pp;
+}
+
+static void
+sacpathfree(SacPath *p)
+{
+ if(p == nil)
+ return;
+ if(decref(p) > 0)
+ return;
+ sacpathfree(p->up);
+ free(p);
+}
+
+
+static void
+sacfree(Sac *s)
+{
+ sacpathfree(s->path);
+ free(s);
+}
+
+static void
+sacdir(Chan *c, SacDir *s, char *buf)
+{
+ Dir dir;
+
+ memmove(dir.name, s->name, NAMELEN);
+ dir.qid = (Qid){getl(s->qid), 0};
+ dir.mode = getl(s->mode);
+ dir.length = getl(s->length);
+ if(dir.mode &CHDIR)
+ dir.length *= DIRLEN;
+ memmove(dir.uid, s->uid, NAMELEN);
+ memmove(dir.gid, s->gid, NAMELEN);
+ dir.atime = getl(s->atime);
+ dir.mtime = getl(s->mtime);
+ dir.type = devtab[c->type]->dc;
+ dir.dev = c->dev;
+ convD2M(&dir, buf);
+}
+
+static void
+loadblock(void *buf, uchar *offset, int blocksize)
+{
+ long block, n;
+ ulong age;
+ int i, j;
+
+ block = getl(offset);
+ if(block < 0) {
+ block = -block;
+ cacheage++;
+ // age has wraped
+ if(cacheage == 0) {
+ for(i=0; i<CacheSize; i++)
+ cache[i].age = 0;
+ }
+ j = 0;
+ age = cache[0].age;
+ for(i=0; i<CacheSize; i++) {
+ if(cache[i].age < age) {
+ age = cache[i].age;
+ j = i;
+ }
+ if(cache[i].block != block)
+ continue;
+ memmove(buf, cache[i].data, blocksize);
+ cache[i].age = cacheage;
+ return;
+ }
+
+ n = getl(offset+OffsetSize);
+ if(n < 0)
+ n = -n;
+ n -= block;
+ if(unsac(buf, data+block, blocksize, n)<0)
+ panic("unsac failed!");
+ memmove(cache[j].data, buf, blocksize);
+ cache[j].age = cacheage;
+ cache[j].block = block;
+ } else {
+ memmove(buf, data+block, blocksize);
+ }
+}
+
+static Sac*
+sacparent(Sac *s)
+{
+ uchar *blocks;
+ SacDir *buf;
+ int per, i, n;
+ SacPath *p;
+
+ p = s->path;
+ if(p == nil || p->up == nil) {
+ sacpathfree(p);
+ *s = root;
+ return s;
+ }
+ p = p->up;
+
+ blocks = data + p->blocks;
+ per = blocksize/sizeof(SacDir);
+ i = p->entry/per;
+ n = per;
+ if(n > p->nentry-i*per)
+ n = p->nentry-i*per;
+ buf = malloc(per*sizeof(SacDir));
+ loadblock(buf, blocks + i*OffsetSize, n*sizeof(SacDir));
+ s->SacDir = buf[p->entry-i*per];
+ free(buf);
+ incref(p);
+ sacpathfree(s->path);
+ s->path = p;
+ return s;
+}
+
+static int
+sacdirread(Chan *c, char *p, long off, long cnt)
+{
+ uchar *blocks;
+ SacDir *buf;
+ int iblock, per, i, j, n, ndir;
+ Sac *s;
+
+ s = c->aux;
+ blocks = data + getl(s->blocks);
+ per = blocksize/sizeof(SacDir);
+ ndir = getl(s->length);
+ off /= DIRLEN;
+ cnt /= DIRLEN;
+ if(off >= ndir)
+ return 0;
+ if(cnt > ndir-off)
+ cnt = ndir-off;
+ iblock = -1;
+ buf = malloc(per*sizeof(SacDir));
+ for(i=off; i<off+cnt; i++) {
+ j = i/per;
+ if(j != iblock) {
+ n = per;
+ if(n > ndir-j*per)
+ n = ndir-j*per;
+ loadblock(buf, blocks + j*OffsetSize, n*sizeof(SacDir));
+ iblock = j;
+ }
+ j *= per;
+ sacdir(c, buf+i-j, p);
+ p += DIRLEN;
+ }
+ free(buf);
+ return cnt*DIRLEN;
+}
+
+static Sac*
+saclookup(Sac *s, char *name)
+{
+ int ndir;
+ int i, j, k, n, per;
+ uchar *blocks;
+ SacDir *buf;
+ int iblock;
+ SacDir *sd;
+
+ if(strcmp(name, "..") == 0)
+ return sacparent(s);
+ blocks = data + getl(s->blocks);
+ per = blocksize/sizeof(SacDir);
+ ndir = getl(s->length);
+ buf = malloc(per*sizeof(SacDir));
+ iblock = -1;
+
+ // linear search
+ for(i=0; i<ndir; i++) {
+ j = i/per;
+ if(j != iblock) {
+ n = per;
+ if(n > ndir-j*per)
+ n = ndir-j*per;
+ loadblock(buf, blocks + j*OffsetSize, n*sizeof(SacDir));
+ iblock = j;
+ }
+ j *= per;
+ sd = buf+i-j;
+ k = strcmp(name, sd->name);
+ if(k == 0) {
+ s->path = sacpathalloc(s->path, getl(s->blocks), i, ndir);
+ s->SacDir = *sd;
+ free(buf);
+ return s;
+ }
+ }
+ free(buf);
+ return 0;
+}
+
+static ulong
+getl(void *p)
+{
+ uchar *a = p;
+
+ return (a[0]<<24) | (a[1]<<16) | (a[2]<<8) | a[3];
+}
+
+Dev sacdevtab = {
+ 'C',
+ "sac",
+
+ devreset,
+ sacinit,
+ sacattach,
+ sacclone,
+ sacwalk,
+ sacstat,
+ sacopen,
+ devcreate,
+ sacclose,
+ sacread,
+ devbread,
+ sacwrite,
+ devbwrite,
+ devremove,
+ devwstat,
+};
M bitsy/devuart.c => bitsy/devuart.c +195 -4
@@ 20,9 20,18 @@ static int uartndir;
*/
static char Ekinuse[] = "device in use by kernel";
+struct Uartalloc {
+ Lock;
+ Uart *elist; /* list of enabled interfaces */
+} uartalloc;
+
static void uartdcdhup(Uart*, int);
static void uartdcdts(Uart*, int);
static void uartdsrhup(Uart*, int);
+static void uartenable(Uart*);
+static void uartdisable(Uart*);
+static void uartclock(void);
+static void uartflow(void*);
/*
* define a Uart
@@ 54,8 63,8 @@ uartsetup(PhysUart *phys, void *regs, ulong freq, char *name)
(*p->phys->baud)(p, 115200);
(*p->phys->enable)(p, 0);
- p->iq = qopen(4*1024, 0, p->phys->flow, p);
- p->oq = qopen(4*1024, 0, p->phys->kick, p);
+ p->iq = qopen(4*1024, 0, uartflow, p);
+ p->oq = qopen(4*1024, 0, uartkick, p);
if(p->iq == nil || p->oq == nil)
panic("uartsetup");
@@ 66,6 75,52 @@ uartsetup(PhysUart *phys, void *regs, ulong freq, char *name)
return p;
}
+/*
+ * enable/diable uart and add/remove to list of enabled uarts
+ */
+static void
+uartenable(Uart *p)
+{
+ Uart **l;
+
+ p->hup_dsr = p->hup_dcd = 0;
+ p->dsr = p->dcd = 0;
+
+ /* assume we can send */
+ p->cts = 1;
+
+ (*p->phys->enable)(p, 1);
+
+ lock(&uartalloc);
+ for(l = &uartalloc.elist; *l; l = &(*l)->elist){
+ if(*l == p)
+ break;
+ }
+ if(*l == 0){
+ p->elist = uartalloc.elist;
+ uartalloc.elist = p;
+ }
+ p->enabled = 1;
+ unlock(&uartalloc);
+}
+static void
+uartdisable(Uart *p)
+{
+ Uart **l;
+
+ (*p->phys->disable)(p);
+
+ lock(&uartalloc);
+ for(l = &uartalloc.elist; *l; l = &(*l)->elist){
+ if(*l == p){
+ *l = p->elist;
+ break;
+ }
+ }
+ p->enabled = 0;
+ unlock(&uartalloc);
+}
+
static void
setlength(int i)
{
@@ 109,6 164,8 @@ uartreset(void)
dp->perm = 0444;
dp++;
}
+
+ addclock0link(uartclock);
}
@@ 147,7 204,7 @@ uartopen(Chan *c, int omode)
error(Ekinuse);
qlock(p);
if(p->opens++ == 0){
- (*p->phys->enable)(p, 1);
+ uartenable(p);
qreopen(p->iq);
qreopen(p->oq);
}
@@ 175,7 232,7 @@ uartclose(Chan *c)
error(Ekinuse);
qlock(p);
if(--(p->opens) == 0){
- (*p->phys->disable)(p);
+ uartdisable(p);
qclose(p->iq);
qclose(p->oq);
p->ip = p->istage;
@@ 400,6 457,23 @@ uartdcdts(Uart *p, int n)
}
/*
+ * restart input if it's off
+ */
+static void
+uartflow(void *v)
+{
+ Uart *p;
+
+ p = v;
+ if(p->modem){
+ (*p->phys->rts)(p, 1);
+ ilock(&p->rlock);
+ p->haveinput = 1;
+ iunlock(&p->rlock);
+ }
+}
+
+/*
* put some bytes into the local queue to avoid calling
* qconsume for every character
*/
@@ 415,3 489,120 @@ uartstageoutput(Uart *p)
p->oe = p->ostage + n;
return n;
}
+
+/*
+ * restart output
+ */
+void
+uartkick(void *v)
+{
+ Uart *p = v;
+
+ ilock(&p->tlock);
+ (*p->phys->kick)(p);
+ iunlock(&p->tlock);
+}
+
+/*
+ * streceiveage a character at interrupt time
+ */
+void
+uartrecv(Uart *p, char ch)
+{
+ /* software flow control */
+ if(p->xonoff){
+ if(ch == CTLS){
+ p->blocked = 1;
+ }else if (ch == CTLQ){
+ p->blocked = 0;
+ p->ctsbackoff = 2; /* clock gets output going again */
+ }
+ }
+
+ /* receive the character */
+ if(p->putc)
+ p->putc(p->iq, ch);
+ else {
+ ilock(&p->rlock);
+ if(p->ip < p->ie)
+ *p->ip++ = ch;
+ p->haveinput = 1;
+ iunlock(&p->rlock);
+ }
+}
+
+/*
+ * we save up input characters till clock time to reduce
+ * per character interrupt overhead.
+ *
+ * There's also a bit of code to get a stalled print going.
+ * It shouldn't happen, but it does. Obviously I don't
+ * understand something. Since it was there, I bundled a
+ * restart after flow control with it to give some hysteresis
+ * to the hardware flow control. This makes compressing
+ * modems happier but will probably bother something else.
+ * -- presotto
+ */
+static void
+uartclock(void)
+{
+ int n;
+ Uart *p;
+
+ for(p = uartalloc.elist; p; p = p->elist){
+
+ /* this amortizes cost of qproduce to many chars */
+ if(p->haveinput){
+ ilock(&p->rlock);
+ if(p->haveinput){
+ n = p->ip - p->istage;
+ if(n > 0 && p->iq){
+ if(n > Stagesize)
+ panic("uartclock");
+ if(qproduce(p->iq, p->istage, n) < 0)
+ (*p->phys->rts)(p, 0);
+ else
+ p->ip = p->istage;
+ }
+ p->haveinput = 0;
+ }
+ iunlock(&p->rlock);
+ }
+ if(p->dohup){
+ ilock(&p->rlock);
+ if(p->dohup){
+ qhangup(p->iq, 0);
+ qhangup(p->oq, 0);
+ }
+ p->dohup = 0;
+ iunlock(&p->rlock);
+ }
+
+ /* this adds hysteresis to hardware/software flow control */
+ if(p->ctsbackoff){
+ ilock(&p->tlock);
+ if(p->ctsbackoff){
+ if(--(p->ctsbackoff) == 0)
+ (*p->phys->kick)(p);
+ }
+ iunlock(&p->tlock);
+ }
+ }
+}
+
+/*
+ * configure a uart port as a console or a mouse
+ */
+void
+uartspecial(Uart *p, int baud, Queue **in, Queue **out, int (*putc)(Queue*, int))
+{
+ uartenable(p);
+ if(baud)
+ (*p->phys->baud)(p, baud);
+ p->putc = putc;
+ if(in)
+ *in = p->iq;
+ if(out)
+ *out = p->oq;
+ p->opens++;
+}
M bitsy/fns.h => bitsy/fns.h +8 -6
@@ 1,15 1,13 @@
#include "../port/portfns.h"
+void cacheflush(void);
+void cacheflushaddr(ulong);
int cistrcmp(char*, char*);
int cistrncmp(char*, char*, int);
-void cleancache(void);
-void cleanaddr(ulong);
-#define clearmmucache() /* x86 doesn't have one */
void clockinit(void);
#define coherence()
void delay(int);
void evenaddr(ulong);
-void flushcache(void);
void flushmmu(void);
ulong getfar(void);
ulong getfsr(void);
@@ 28,6 26,7 @@ void meminit(void);
void mmuinit(void);
void mmuenable(void);
void mmudisable(void);
+void mmuinvalidate(void);
void noted(Ureg*, ulong);
int notify(Ureg*);
#define procrestore(p)
@@ 40,16 39,19 @@ void qpanic(char *, ...);
void reset(void);
void rs232power(int);
Uart* uartsetup(PhysUart*, void*, ulong, char*);
-void sa1100_uartsetup(void);
+void uartspecial(Uart*, int, Queue**, Queue**, int (*)(Queue*, int));
+void sa1100_uartsetup(int);
void screeninit(void);
int screenprint(char*, ...); /* debugging */
-void (*screenputs)(char*, int);
+void screenputs(char*, int);
void setr13(int, ulong*);
void touser(void*);
void trapdump(char *tag);
void trapinit(void);
int tas(void*);
int uartstageoutput(Uart*);
+void uartkick(void*);
+void uartrecv(Uart*, char);
void vectors(void);
void vtable(void);
void wbflush(void);
M bitsy/io.h => bitsy/io.h +1 -2
@@ 98,8 98,7 @@ struct PhysUart
{
void (*enable)(Uart*, int);
void (*disable)(Uart*);
- void (*kick)(void*);
- void (*flow)(void*);
+ void (*kick)(Uart*);
void (*intr)(Ureg*, void*);
void (*dobreak)(Uart*, int);
void (*baud)(Uart*, int);
M bitsy/l.s => bitsy/l.s +8 -19
@@ 35,12 35,12 @@ _mainloop:
BL _div(SB) /* hack to get _div etc loaded */
/* flush tlb's */
-TEXT flushmmu(SB), $-4
+TEXT mmuinvalidate(SB), $-4
MCR CpMMU, 0, R0, C(CpTLBFlush), C(0x7)
RET
-/* clean and flush i and d caches */
-TEXT cleancache(SB), $-4
+/* write back and invalidate i and d caches */
+TEXT cacheflush(SB), $-4
/* write back any dirty data */
MOVW $0xe0000000,R0
ADD $(8*1024),R0,R1
@@ 49,7 49,8 @@ _wbloop:
CMP R0,R1
BNE _wbloop
- /* flush cache contents */
+ /* drain write buffer and flush i&d cache contents */
+ MCR CpMMU, 0, R0, C(CpCacheFlush), C(0xa), 4
MCR CpMMU, 0, R0, C(CpCacheFlush), C(0x7), 0
/* drain prefetch */
@@ 60,22 61,10 @@ _wbloop:
RET
/* clean a single virtual address */
-TEXT cleanaddr(SB), $-4
+TEXT cacheflushaddr(SB), $-4
MCR CpMMU, 0, R0, C(CpCacheFlush), C(0xa), 1
RET
-/* flush i and d caches */
-TEXT flushcache(SB), $-4
- /* flush cache contents */
- MCR CpMMU, 0, R0, C(CpCacheFlush), C(0x7), 0
-
- /* drain prefetch */
- MOVW R0,R0
- MOVW R0,R0
- MOVW R0,R0
- MOVW R0,R0
- RET
-
/* drain write buffer */
TEXT wbflush(SB), $-4
MCR CpMMU, 0, R0, C(CpCacheFlush), C(0xa), 4
@@ 111,13 100,13 @@ TEXT putttb(SB), $-4
*/
TEXT mmuenable(SB), $-4
MRC CpMMU, 0, R0, C(CpControl), C(0x0)
- ORR $(CpCmmuena), R0
+ ORR $(CpCmmuena|CpCwb|CpCdcache), R0
MCR CpMMU, 0, R0, C(CpControl), C(0x0)
RET
TEXT mmudisable(SB), $-4
MRC CpMMU, 0, R0, C(CpControl), C(0x0)
- BIC $(CpCmmuena|CpCvivec), R0
+ BIC $(CpCmmuena|CpCdcache|CpCwb|CpCvivec), R0
MCR CpMMU, 0, R0, C(CpControl), C(0x0)
RET
M bitsy/main.c => bitsy/main.c +7 -10
@@ 18,7 18,7 @@ int noprint;
void
main(void)
{
- cleancache();
+ mmuinvalidate();
/* zero out bss */
memset(edata, 0, end-edata);
@@ 31,22 31,20 @@ main(void)
rs232power(1);
iprint("bitsy kernel\n");
confinit();
- iprint("%d pages %lux(%lud) %lux(%lud)\n", conf.npage, conf.base0, conf.npage0, conf.base1, conf.npage1);
xinit();
mmuinit();
- sa1100_uartsetup();
gpioinit();
trapinit();
- printinit();
+ sa1100_uartsetup(1);
+ printinit(); /* from here on, print works, before this we need iprint */
clockinit();
procinit0();
initseg();
chandevreset();
-noprint = 1;
pageinit();
swapinit();
userinit();
-iprint("schedinit(), death soon\n");
+//iprint("schedinit(), death soon\n");
schedinit();
}
@@ 62,6 60,7 @@ exit(int ispanic)
delay(1000);
iprint("it's a wonderful day to die\n");
+ mmuinvalidate();
mmudisable();
f = nil;
(*f)();
@@ 210,7 209,6 @@ userinit(void)
strcpy(p->text, "*init*");
strcpy(p->user, eve);
-
/*
* Kernel Stack
*/
@@ 239,9 237,7 @@ userinit(void)
k = kmap(s->map[0]->pages[0]);
memmove((ulong*)VA(k), initcode, sizeof initcode);
kunmap(k);
- cleancache();
- wbflush();
-iprint("userinit %lux[0x20] = %lux\n", VA(k), *((ulong*)(VA(k)+0x20)));
+//iprint("userinit %lux[0x20] = %lux\n", VA(k), *((ulong*)(VA(k)+0x20)));
ready(p);
}
@@ 361,6 357,7 @@ confinit(void)
conf.upages = (conf.npage*40)/100;
conf.ialloc = ((conf.npage-conf.upages)/2)*BY2PG;
+ /* only one processor */
conf.nmach = 1;
/* set up other configuration parameters */
M bitsy/mmu.c => bitsy/mmu.c +64 -13
@@ 82,6 82,7 @@ mmuinit(void)
/* map zeros area */
for(o = 0; o < 128 * OneMeg; o += OneMeg)
l1table[(NULLZERO+o)>>20] = L1Section | L1KernelRW | L1Domain0
+ | L1Cached | L1Buffered
| ((PHYSNULL0+o)&L1SectBaseMask);
/* map flash */
@@ 113,9 114,9 @@ mmuinit(void)
/* enable mmu */
wbflush();
- flushcache();
- flushmmu();
+ mmuinvalidate();
mmuenable();
+ cacheflush();
}
/*
@@ 224,7 225,7 @@ putmmu(ulong va, ulong pa, Page*)
Page *p;
ulong *t;
-iprint("putmmu(0x%.8lux, 0x%.8lux)\n", va, pa);
+//iprint("putmmu(0x%.8lux, 0x%.8lux)\n", va, pa);
/* always point L1 entry to L2 page, can't hurt */
p = up->l1page[va>>20];
if(p == nil){
@@ 236,47 237,97 @@ iprint("putmmu(0x%.8lux, 0x%.8lux)\n", va, pa);
memset((uchar*)(p->va), 0, BY2PG);
}
l1table[va>>20] = L1PageTable | L1Domain0 | (p->pa & L1PTBaseMask);
- cleanaddr((ulong)&l1table[va>>20]);
-iprint("%lux[%lux] = %lux\n", l1table, va>>20, l1table[va>>20]);
+ cacheflushaddr((ulong)&l1table[va>>20]);
+//iprint("%lux[%lux] = %lux\n", l1table, va>>20, l1table[va>>20]);
up->l1table[va>>20] = l1table[va>>20];
t = (ulong*)p->va;
/* set L2 entry */
t[(va & (OneMeg-1))>>PGSHIFT] = mmubits[pa & (PTEKERNEL|PTEVALID|PTEUNCACHED|PTEWRITE)]
| (pa & ~(PTEKERNEL|PTEVALID|PTEUNCACHED|PTEWRITE));
-iprint("%lux[%lux] = %lux\n", (ulong)t, (va & (OneMeg-1))>>PGSHIFT, t[(va & (OneMeg-1))>>PGSHIFT]);
- cleanaddr((ulong)&t[(va & (OneMeg-1))>>PGSHIFT]);
+//iprint("%lux[%lux] = %lux\n", (ulong)t, (va & (OneMeg-1))>>PGSHIFT, t[(va & (OneMeg-1))>>PGSHIFT]);
+ cacheflushaddr((ulong)&t[(va & (OneMeg-1))>>PGSHIFT]);
wbflush();
}
/*
- * this is called with palloc locked so the pagechainhead is kosher
+ * free up all page tables for this proc
*/
void
-mmurelease(Proc* p)
+mmuptefree(Proc *p)
{
Page *pg;
int i;
- for(i = 0; i < nelem(p->l1page); i++){
+ for(i = 0; i < Nmeg; i++){
pg = p->l1page[i];
if(pg == nil)
continue;
+ p->l1page[i] = nil;
+ pg->next = p->mmufree;
+ p->mmufree = pg;
+ }
+ memset(p->l1table, 0, sizeof(p->l1table));
+}
+
+/*
+ * this is called with palloc locked so the pagechainhead is kosher
+ */
+void
+mmurelease(Proc* p)
+{
+ Page *pg, *next;
+
+ /* write back dirty cache entries before changing map */
+ cacheflush();
+
+ mmuptefree(p);
+
+ for(pg = p->mmufree; pg; pg = next){
+ next = pg->next;
if(--pg->ref)
panic("mmurelease: pg->ref %d\n", pg->ref);
pagechainhead(pg);
- p->l1page[i] = nil;
}
+ if(p->mmufree && palloc.r.p)
+ wakeup(&palloc.r);
+ p->mmufree = nil;
+
+ memset(l1table, 0, sizeof(p->l1table));
}
void
mmuswitch(Proc* p)
{
-iprint("switching to proc %d\n", p->pid);
+ if(p->newtlb){
+ mmuptefree(p);
+ p->newtlb = 0;
+ }
+
+ /* write back dirty cache entries before changing map */
+ cacheflush();
+
+ /* move in new map */
memmove(l1table, p->l1table, sizeof(p->l1table));
- cleanaddr((ulong)l1table);
+
+ /* make sure map is in memory and drain write buffer */
+ cacheflushaddr((ulong)l1table);
wbflush();
+
+ /* lose any possible stale tlb entries */
+ mmuinvalidate();
+}
+
+void
+flushmmu(void)
+{
+ int s;
+
+ s = splhi();
+ up->newtlb = 1;
+ mmuswitch(up);
+ splx(s);
}
void
M bitsy/screen.c => bitsy/screen.c +6 -0
@@ 42,3 42,9 @@ blankscreen(int blank)
{
USED(blank);
}
+
+void
+screenputs(char *s, int n)
+{
+ USED(s, n);
+}
M bitsy/trap.c => bitsy/trap.c +26 -23
@@ 131,14 131,15 @@ faultarm(Ureg *ureg, ulong va, int user, int read)
insyscall = up->insyscall;
up->insyscall = 1;
-peekmmu(va);
+//peekmmu(va);
n = fault(va, read);
-iprint("fault returns %d\n", n);
+//iprint("fault returns %d\n", n);
if(n < 0){
if(!user){
dumpregs(ureg);
- qpanic("fault: 0x%lux\n", va);
+ panic("fault: 0x%lux\n", va);
}
+ dumpregs(ureg);
sprint(buf, "sys: trap: fault %s va=0x%lux",
read? "read" : "write", va);
postnote(up, 1, buf, NDebug);
@@ 152,7 153,7 @@ iprint("fault returns %d\n", n);
void
trap(Ureg *ureg)
{
- int i;
+ int i, found;
Vctl *v;
int user;
ulong va;
@@ 171,18 172,18 @@ trap(Ureg *ureg)
switch(ureg->type){
default:
- qpanic("unknown trap");
+ panic("unknown trap");
break;
case PsrMabt: /* prefetch fault */
- iprint("prefetch abort at 0x%lux\n", ureg->pc);
+//iprint("prefetch abort at 0x%lux\n", ureg->pc);
faultarm(ureg, ureg->pc, user, 1);
break;
case PsrMabt+1: /* data fault */
va = getfar();
- iprint("data fault pc 0x%lux va 0x%lux fsr 0x%lux\n", ureg->pc, va, getfsr());
+//iprint("data fault pc 0x%lux(0x%lux) va 0x%lux fsr 0x%lux\n", ureg->pc, *(ulong*)(ureg->pc), va, getfsr());
switch(getfsr() & 0xf){
case 0x0:
- qpanic("vector exception at %lux\n", ureg->pc);
+ panic("vector exception at %lux\n", ureg->pc);
break;
case 0x1:
case 0x3:
@@ 191,10 192,10 @@ trap(Ureg *ureg)
ureg->pc, va);
postnote(up, 1, buf, NDebug);
} else
- qpanic("kernel alignment: pc 0x%lux va 0x%lux", ureg->pc, va);
+ panic("kernel alignment: pc 0x%lux va 0x%lux", ureg->pc, va);
break;
case 0x2:
- qpanic("terminal exception at %lux\n", ureg->pc);
+ panic("terminal exception at %lux\n", ureg->pc);
break;
case 0x4:
case 0x6:
@@ 202,12 203,12 @@ trap(Ureg *ureg)
case 0xa:
case 0xc:
case 0xe:
- qpanic("external abort at %lux\n", ureg->pc);
+ panic("external abort at %lux\n", ureg->pc);
break;
case 0x5:
case 0x7:
/* translation fault, i.e., no pte entry */
- faultarm(ureg, va, user, 0);
+ faultarm(ureg, va, user, 1);
break;
case 0x9:
case 0xb:
@@ 216,24 217,30 @@ trap(Ureg *ureg)
sprint(buf, "sys: access violation: pc 0x%lux va 0x%lux\n", ureg->pc, va);
postnote(up, 1, buf, NDebug);
} else
- qpanic("kernel access violation: pc 0x%lux va 0x%lux\n", ureg->pc, va);
+ panic("kernel access violation: pc 0x%lux va 0x%lux\n", ureg->pc, va);
break;
case 0xd:
case 0xf:
/* permission error, copy on write or real permission error */
- faultarm(ureg, va, user, 1);
+ faultarm(ureg, va, user, 0);
break;
}
break;
case PsrMund: /* undefined instruction */
- qpanic("undefined instruction");
+ panic("undefined instruction");
break;
case PsrMirq: /* device interrupt */
- for(i = 0; i < 32; i++)
+ for(i = 0; i < 32; i++){
+ found = 0;
if((1<<i) & intrregs->icip){
- for(v = vctl[i]; v != nil; v = v->next)
+ for(v = vctl[i]; v != nil; v = v->next){
+ found = 1;
v->f(ureg, v->a);
+ }
+ if(!found)
+ iprint("interrupt %d with no handler\n", i);
}
+ }
break;
}
@@ 258,10 265,8 @@ syscall(Ureg* ureg)
long ret;
int i, scallnr;
-iprint("syscall in\n");
-dumpregs(ureg);
if((ureg->psr & PsrMask) != PsrMusr)
- qpanic("syscall: cs 0x%4.4uX\n", ureg->psr);
+ panic("syscall: cs 0x%4.4uX\n", ureg->psr);
m->syscall++;
up->insyscall = 1;
@@ 289,9 294,7 @@ dumpregs(ureg);
up->s = *((Sargs*)(sp+BY2WD));
up->psstate = sysctab[scallnr];
-iprint("before syscall\n");
ret = systab[scallnr](up->s.args);
-iprint("syscall retuns %d\n", ret);
poperror();
}
if(up->nerrlab){
@@ 299,7 302,7 @@ iprint("syscall retuns %d\n", ret);
for(i = 0; i < NERR; i++)
print("sp=%lux pc=%lux\n",
up->errlab[i].sp, up->errlab[i].pc);
- qpanic("error stack");
+ panic("error stack");
}
up->insyscall = 0;