M gnot/mmu.c => gnot/mmu.c +1 -1
@@ 127,7 127,7 @@ kmapinit(void)
return;
}
e = (4*1024*1024 - 256*1024)/BY2PG; /* screen lives at top 256K */
- i = (((ulong)ialloc(0, 0))&~KZERO)/BY2PG;
+ i = PGROUND(((ulong)ialloc(0, 0))&~KZERO)/BY2PG;
print("%lud free map registers\n", e-i);
kmapalloc.free = 0;
for(k=&kmapalloc.arena[i]; i<e; i++,k++){
M pc/bbmalloc.c => pc/bbmalloc.c +6 -0
@@ 15,6 15,9 @@
* address in non-cached space, the need for flushing the
* d-cache is avoided.
*
+ * On the safari, all this is unnecessary, since the
+ * only icache is a miniscule prefetch buffer.
+ *
* Currently, the only kernel users of bitblt are devbit,
* print, and the cursor stuff in devbit. The cursor
* can get drawn at clock interrupt time, so it might need
@@ 61,9 64,12 @@ void
bbfree(void *p, int n)
{
ulong *up;
+ int s;
+ s = splhi();
if(p == bblast)
bbcur = (ulong *)(((char *)bblast) + n);
+ splx(s);
}
void *
M pc/clock.c => pc/clock.c +6 -2
@@ 70,12 70,16 @@ clock(Ureg *ur)
p->time[p->insyscall]++;
}
-/* if(u && p && p->state==Running){
+ if(u && p && p->state==Running){
if(anyready()){
if(p->hasspin)
p->hasspin = 0;
else
sched();
}
- }/**/
+ if((ur->cs&0xffff) == UESEL){ /* if was in user mode */
+ if(u->nnote)
+ notify(ur);
+ }
+ }
}
M pc/devfloppy.c => pc/devfloppy.c +170 -85
@@ 4,11 4,11 @@
#include "dat.h"
#include "fns.h"
#include "io.h"
-#include "ureg.h"
+#include "errno.h"
-typedef struct Drive Drive;
+typedef struct Drive Drive;
typedef struct Controller Controller;
-typedef struct Type Type;
+typedef struct Type Type;
enum
{
@@ 46,8 46,9 @@ enum
/* file types */
Qdir= 0,
- Qdata= 1,
- Qstruct= 2,
+ Qdata= (1<<2),
+ Qstruct= (2<<2),
+ Qmask= (3<<2),
};
/*
@@ 82,7 83,9 @@ Type floppytype[] =
#define NTYPES (sizeof(floppytype)/sizeof(Type))
/*
- * bytes/sector encoding for the controller, index is (bytes per sector/128)
+ * bytes per sector encoding for the controller.
+ * - index for b2c is is (bytes per sector/128).
+ * - index for c2b is code from b2c
*/
static int b2c[] =
{
@@ 112,7 115,6 @@ struct Drive
ulong lasttouched; /* time last touched */
int motoron; /* motor is on */
int cyl; /* current cylinder */
- long offset; /* current offset */
int confused; /* needs to be recalibrated (or worse) */
int tcyl; /* target cylinder */
@@ 120,7 122,6 @@ struct Drive
int tsec; /* target sector */
long len; /* size of xfer */
- int busy; /* true if drive is seeking */
Rendez r; /* waiting here for motor to spin up */
};
@@ 132,11 133,12 @@ struct Controller
QLock; /* exclusive access to the contoller */
Drive d[Ndrive]; /* the floppy drives */
- int busy; /* true if a read or write in progress */
uchar stat[8]; /* status of an operation */
int confused;
int intr; /* true if interrupt occured */
Rendez r; /* wait here for command termination */
+
+ Rendez kr; /* for motor watcher */
};
Controller floppy;
@@ 150,46 152,50 @@ static void floppykproc(void*);
static int floppysend(int);
static int floppyrcv(void);
static int floppyresult(int);
-static void floppypos(Drive*);
+static void floppypos(Drive*,long);
static int floppysense(Drive*);
static int interrupted(void*);
static int floppyrecal(Drive*);
static void floppyrevive(void);
static long floppyseek(Drive*);
-static long floppyxfer(Drive*, int, void*, long);
+static long floppyxfer(Drive*, int, void*, long, long);
static void floppyintr(Ureg*);
-static int
-floppygen(Chan *c, Dirtab *tab, long ntab, long s, Dir *dp)
-{
- long l;
- Drive *dp;
-
- if(s >= ntab)
- return -1;
- if(c->dev >= Ndrive)
- return -1;
-
- tab += s;
- dp = &floppy.d[c->dev];
- if((tab->qid.path&~Mask) == Qdata)
- l = dp->t->cap;
- else
- l = 8;
- devdir(c, tab->qid, tab->name, l, tab->perm, dp);
- return 1;
-}
+Dirtab floppydir[]={
+ "fd0data", {Qdata + 0}, 0, 0600,
+ "fd0struct", {Qstruct + 0}, 8, 0600,
+ "fd1data", {Qdata + 1}, 0, 0600,
+ "fd1struct", {Qstruct + 1}, 8, 0600,
+ "fd2data", {Qdata + 2}, 0, 0600,
+ "fd2struct", {Qstruct + 2}, 8, 0600,
+ "fd3data", {Qdata + 3}, 0, 0600,
+ "fd3struct", {Qstruct + 3}, 8, 0600,
+};
+#define NFDIR (sizeof(floppydir)/sizeof(Dirtab))
void
floppyreset(void)
{
Drive *dp;
+ Type *t;
+
+ /*
+ * init dependent parameters
+ */
+ for(t = floppytype; t < &floppytype[NTYPES]; t++){
+ t->cap = t->bytes * t->heads * t->sectors * t->tracks;
+ t->bcode = b2c[t->bytes/128];
+ }
+ /*
+ * stop the motors
+ */
for(dp = floppy.d; dp < &floppy.d[Ndrive]; dp++){
dp->dev = dp - floppy.d;
dp->t = &floppytype[0]; /* default type */
+ floppydir[2*dp->dev].length = dp->t->cap;
dp->motoron = 1;
- dp->cyl = -1;
+ dp->cyl = -1; /* because we don't know */
motoroff(dp);
}
setvec(Floppyvec, floppyintr);
@@ 198,21 204,74 @@ floppyreset(void)
void
floppyinit(void)
{
- Type *t;
-
- /*
- * init dependent parameters
- */
- for(t = floppytype; t < &floppytype[NTYPES], t++){
- t->cap = t->bytes * t->heads * t->sectors * t->tracks;
- t->bcode = bcode[t->bytes/128];
- }
-
/*
* watchdog to turn off the motors
*/
- kproc(floppykproc, 0);
+ kproc("floppy", floppykproc, 0);
+}
+
+Chan*
+floppyattach(char *spec)
+{
+ return devattach('f', spec);
}
+
+Chan*
+floppyclone(Chan *c, Chan *nc)
+{
+ return devclone(c, nc);
+}
+
+int
+floppywalk(Chan *c, char *name)
+{
+ return devwalk(c, name, floppydir, NFDIR, devgen);
+}
+
+void
+floppystat(Chan *c, char *dp)
+{
+ devstat(c, dp, floppydir, NFDIR, devgen);
+}
+
+Chan*
+floppyopen(Chan *c, int omode)
+{
+ return devopen(c, omode, floppydir, NFDIR, devgen);
+}
+
+void
+floppycreate(Chan *c, char *name, int omode, ulong perm)
+{
+ error(Eperm);
+}
+
+void
+floppyclose(Chan *c)
+{
+}
+
+void
+floppyremove(Chan *c)
+{
+ error(Eperm);
+}
+
+void
+floppywstat(Chan *c, char *dp)
+{
+ error(Eperm);
+}
+
+static void
+ul2user(uchar *a, ulong x)
+{
+ a[0] = x >> 24;
+ a[1] = x >> 16;
+ a[2] = x >> 8;
+ a[3] = x;
+}
+
long
floppyread(Chan *c, void *a, long n)
{
@@ 220,11 279,30 @@ floppyread(Chan *c, void *a, long n)
long rv, i;
uchar *aa = a;
- dp = &floppy.d[c->dev];
- for(rv = 0; rv < n; rv += i){
- i = floppyxfer(dp, Fread, aa+rv, n-rv);
- if(i <= 0)
- break;
+ if(c->qid.path == CHDIR)
+ return devdirread(c, a, n, floppydir, NFDIR, devgen);
+
+ rv = 0;
+ dp = &floppy.d[c->qid.path & ~Qmask];
+ switch ((int)(c->qid.path & Qmask)) {
+ case Qdata:
+ for(rv = 0; rv < n; rv += i){
+ i = floppyxfer(dp, Fread, aa+rv, c->offset+rv, n-rv);
+ if(i <= 0)
+ break;
+ }
+ break;
+ case Qstruct:
+ if (n < 2*sizeof(ulong))
+ error(Ebadarg);
+ if (c->offset >= 2*sizeof(ulong))
+ return 0;
+ rv = 2*sizeof(ulong);
+ ul2user((uchar*)a, dp->t->cap);
+ ul2user((uchar*)a+sizeof(ulong), dp->t->bytes);
+ break;
+ default:
+ panic("floppyread: bad qid");
}
return rv;
}
@@ 236,17 314,27 @@ floppywrite(Chan *c, void *a, long n)
long rv, i;
uchar *aa = a;
- dp = &floppy.d[c->dev];
- for(rv = 0; rv < n; rv += i){
- i = floppyxfer(dp, Fwrite, aa+rv, n-rv);
- if(i <= 0)
- break;
+ rv = 0;
+ dp = &floppy.d[c->qid.path & ~Qmask];
+ switch ((int)(c->qid.path & Qmask)) {
+ case Qdata:
+ for(rv = 0; rv < n; rv += i){
+ i = floppyxfer(dp, Fwrite, aa+rv, c->offset+rv, n-rv);
+ if(i <= 0)
+ break;
+ }
+ break;
+ case Qstruct:
+ error(Eperm);
+ break;
+ default:
+ panic("floppywrite: bad qid");
}
return rv;
}
/*
- * start a floppy drive's motor. set an alarm for 1 second later to
+ * start a floppy drive's motor. set an alarm for .75 second later to
* mark it as started (we get no interrupt to tell us).
*
* assume the caller qlocked the drive.
@@ 258,10 346,8 @@ motoron(Drive *dp)
cmd = (1<<(dp->dev+4)) | Fintena | Fena | dp->dev;
outb(Fmotor, cmd);
- dp->busy = 1;
- tsleep(&dp->r, noreturn, 0, 1000);
+ tsleep(&dp->r, return0, 0, 750);
dp->motoron = 1;
- dp->busy = 0;
dp->lasttouched = m->ticks;
}
@@ 282,13 368,17 @@ floppykproc(void *a)
{
Drive *dp;
- for(dp = floppy.d; dp < &floppy.d[Ndrive]; dp++){
- if(dp->motoron && TK2SEC(m->ticks - dp->lasttouched) > 5
- && canqlock(dp)){
- if(TK2SEC(m->ticks - dp->lasttouched) > 5)
- motoroff(dp);
- qunlock(dp);
+ waserror();
+ for(;;){
+ for(dp = floppy.d; dp < &floppy.d[Ndrive]; dp++){
+ if(dp->motoron && TK2SEC(m->ticks - dp->lasttouched) > 5
+ && canqlock(dp)){
+ if(TK2SEC(m->ticks - dp->lasttouched) > 5)
+ motoroff(dp);
+ qunlock(dp);
+ }
}
+ tsleep(&floppy.kr, return0, 0, 5*1000);
}
}
@@ 367,13 457,13 @@ floppyresult(int n)
* truncate dp->length if it crosses a cylinder boundary
*/
static void
-floppypos(Drive *dp)
+floppypos(Drive *dp, long off)
{
int lsec;
int end;
int cyl;
- lsec = dp->off/dp->t->bytes;
+ lsec = off/dp->t->bytes;
dp->tcyl = lsec/(dp->t->sectors*dp->t->heads);
dp->tsec = (lsec % dp->t->sectors) + 1;
dp->thead = (lsec/dp->t->sectors) % dp->t->heads;
@@ 382,7 472,7 @@ floppypos(Drive *dp)
* can't read across cylinder boundaries.
* if so, decrement the bytes to be read.
*/
- lsec = (dp->off+dp->len)/dp->t->bytes;
+ lsec = (off+dp->len)/dp->t->bytes;
cyl = lsec/(dp->t->sectors*dp->t->heads);
if(cyl != dp->tcyl){
dp->len -= (lsec % dp->t->sectors)*dp->t->bytes;
@@ 414,7 504,7 @@ floppysense(Drive *dp)
/*
* make sure it's the right drive
*/
- if((floppy.stat[0] & Drivemask) != dp-floppy.d){
+ if((floppy.stat[0] & Drivemask) != dp->dev){
print("sense failed\n");
dp->confused = 1;
return -1;
@@ 517,14 607,14 @@ floppyrevive(void)
static long
floppyseek(Drive *dp)
{
- if(dp->cyl == dp->tcyl){
- dp->offset = off;
- return off;
- }
+ if(dp->cyl == dp->tcyl)
+ return dp->cyl;
/*
* tell floppy to seek
*/
+ floppy.intr = 0;
+ dp->cyl = -1; /* once the seek starts it could end anywhere */
if(floppysend(Fseek) < 0
|| floppysend((dp->thead<<2) | dp->dev) < 0
|| floppysend(dp->tcyl * dp->t->steps) < 0){
@@ 532,10 622,6 @@ floppyseek(Drive *dp)
floppy.confused = 1;
return -1;
}
-
- /*
- * wait for interrupt
- */
sleep(&floppy.r, interrupted, 0);
/*
@@ 563,12 649,11 @@ floppyseek(Drive *dp)
return -1;
}
- dp->offset = off;
- return dp->offset;
+ return dp->cyl;
}
static long
-floppyxfer(Drive *dp, int cmd, void *a, long n)
+floppyxfer(Drive *dp, int cmd, void *a, long off, long n)
{
ulong addr;
long offset;
@@ 577,7 662,7 @@ floppyxfer(Drive *dp, int cmd, void *a, long n)
qlock(&floppy);
qlock(dp);
- if(waserror){
+ if(waserror()){
qunlock(&floppy);
qunlock(dp);
}
@@ 594,7 679,7 @@ floppyxfer(Drive *dp, int cmd, void *a, long n)
* calculate new position and seek to it (dp->len may be trimmed)
*/
dp->len = n;
- floppypos(dp);
+ floppypos(dp, off);
if(floppyseek(dp) < 0)
errors("seeking floppy");
@@ 609,9 694,10 @@ print("tcyl %d, thead %d, tsec %d, addr %lux, n %d\n",
/*
* start operation
*/
+ floppy.intr = 0;
cmd = cmd | (dp->t->heads > 1 ? Fmulti : 0);
if(floppysend(cmd) < 0
- || floppysend((dp->thead<<2) | dev) < 0
+ || floppysend((dp->thead<<2) | dp->dev) < 0
|| floppysend(dp->tcyl * dp->t->steps) < 0
|| floppysend(dp->thead) < 0
|| floppysend(dp->tsec) < 0
@@ 623,7 709,6 @@ print("tcyl %d, thead %d, tsec %d, addr %lux, n %d\n",
floppy.confused = 1;
errors("floppy command failed");
}
-
sleep(&floppy.r, interrupted, 0);
/*
@@ 645,17 730,17 @@ print("xfer failed %lux %lux %lux\n", floppy.stat[0],
offset = (floppy.stat[3]/dp->t->steps) * dp->t->heads + floppy.stat[4];
offset = offset*dp->t->sectors + floppy.stat[5] - 1;
offset = offset * c2b[floppy.stat[6]];
- if(offset != dp->offset+n){
-print("new offset %d instead of %d\n", offset, dp->offset+dp->len);
+ if(offset != off+dp->len){
+print("new offset %d instead of %d\n", offset, off+dp->len);
dp->confused = 1;
errors("floppy drive lost");
}
+ dp->lasttouched = m->ticks;
qunlock(&floppy);
qunlock(dp);
poperror();
- dp->offset += dp->len;
return dp->len;
}
A pc/devhard.c => pc/devhard.c +280 -0
@@ 0,0 1,280 @@
+#include "u.h"
+#include "lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "errno.h"
+
+typedef struct Drive Drive;
+typedef struct Ident Ident;
+typedef struct Controller Controller;
+
+enum
+{
+ /* ports */
+ Pbase= 0x10,
+ Pdata= Pbase+0, /* data port (16 bits) */
+ Perror= Pbase+1, /* error port */
+ Pcount= Pbase+2, /* sector count port */
+ Psector= Pbase+3, /* sector number port */
+ Pcyllsb= Pbase+4, /* least significant byte cylinder # */
+ Pcylmsb= Pbase+5, /* most significant byte cylinder # */
+ Pdh= Pbase+6, /* drive/head port */
+ Pstatus= Pbase+7, /* status port */
+ Pcmd= Pbase+7, /* cmd port */
+
+ /* commands */
+ Crecal= 0x10,
+ Cread= 0x20,
+ Cwrite= 0x30,
+ Cident= 0xEC,
+
+ /* file types */
+ Qdir= 0,
+ Qdata= (1<<1),
+ Qstruct= (2<<1),
+ Qmask= (3<<1),
+};
+
+/*
+ * ident sector from drive
+ */
+struct Ident
+{
+ ushort magic; /* must be 0x0A5A */
+ ushort lcyls; /* logical number of cylinders */
+ ushort rcyl; /* number of removable cylinders */
+ ushort lheads; /* logical number of heads */
+ ushort b2t; /* unformatted bytes/track */
+ ushort b2s; /* unformated bytes/sector */
+ ushort ls2t; /* logical sectors/track */
+ ushort gap; /* bytes in inter-sector gaps */
+ ushort sync; /* bytes in sync fields */
+ ushort magic2; /* must be 0x0000 */
+ ushort serial[10]; /* serial number */
+ ushort type; /* controller type (0x0003) */
+ ushort bsize; /* buffer size/512 */
+ ushort ecc; /* ecc bytes returned by read long */
+ ushort firm[4]; /* firmware revision */
+ ushort model[20]; /* model number */
+ ushort s2i; /* number of sectors/interrupt */
+ ushort dwtf; /* double word transfer flag */
+ ushort alernate;
+ ushort piomode;
+ ushort dmamode;
+ ushort reserved[76];
+ ushort ncyls; /* native number of cylinders */
+ ushort nheads; /* native number of heads, sectors */
+ ushort dlcyls; /* default logical number of cyinders */
+ ushort dlheads; /* default logical number of heads, sectors */
+ ushort interface;
+ ushort power; /* 0xFFFF if power commands supported */
+ ushort flags;
+ ushort ageprog; /* MSB = age, LSB = program */
+ ushort reserved2[120];
+};
+
+/*
+ * a hard drive
+ */
+struct Drive
+{
+ int dev;
+ ulong cap; /* drive capacity */
+ int bytes; /* bytes/sector */
+ int cyl; /* current cylinder */
+ int confused; /* needs to be recalibrated (or worse) */
+
+ int tcyl; /* target cylinder */
+ int thead; /* target head */
+ int tsec; /* target sector */
+ long len; /* size of xfer */
+
+ Ident id;
+};
+
+/*
+ * a controller for 2 drives
+ */
+struct Controller
+{
+ QLock; /* exclusive access to the drive */
+
+ int intr; /* true if interrupt occured */
+ Rendez r; /* wait here for command termination */
+ int confused; /* needs to be recalibrated (or worse) */
+
+ Drive d[2];
+};
+
+Controller hard;
+
+Dirtab harddir[]={
+ "hddata", {Qdata}, 0, 0600,
+ "hdstruct", {Qstruct}, 8, 0600,
+};
+#define NHDIR (sizeof(harddir)/sizeof(Dirtab))
+
+void
+hardreset(void)
+{
+ hard.d[0].dev = 0;
+ hard.d[1].dev = 1;
+ setvec(Hardvec, hardintr);
+}
+
+void
+hardinit(void)
+{
+}
+
+Chan*
+hardattach(char *spec)
+{
+ return devattach('f', spec);
+}
+
+Chan*
+hardclone(Chan *c, Chan *nc)
+{
+ return devclone(c, nc);
+}
+
+int
+hardwalk(Chan *c, char *name)
+{
+ return devwalk(c, name, harddir, NHDIR, devgen);
+}
+
+void
+hardstat(Chan *c, char *dp)
+{
+ devstat(c, dp, harddir, NHDIR, devgen);
+}
+
+Chan*
+hardopen(Chan *c, int omode)
+{
+ return devopen(c, omode, harddir, NHDIR, devgen);
+}
+
+void
+hardcreate(Chan *c, char *name, int omode, ulong perm)
+{
+ error(Eperm);
+}
+
+void
+hardclose(Chan *c)
+{
+}
+
+void
+hardremove(Chan *c)
+{
+ error(Eperm);
+}
+
+void
+hardwstat(Chan *c, char *dp)
+{
+ error(Eperm);
+}
+
+static void
+ul2user(uchar *a, ulong x)
+{
+ a[0] = x >> 24;
+ a[1] = x >> 16;
+ a[2] = x >> 8;
+ a[3] = x;
+}
+
+long
+hardread(Chan *c, void *a, long n)
+{
+ Drive *dp;
+ long rv, i;
+ uchar *aa = a;
+
+ if(c->qid.path == CHDIR)
+ return devdirread(c, a, n, harddir, NHDIR, devgen);
+
+ rv = 0;
+ dp = &hard.d[c->qid.path & ~Qmask];
+ switch ((int)(c->qid.path & Qmask)) {
+ case Qdata:
+ for(rv = 0; rv < n; rv += i){
+ i = hardxfer(dp, Fread, aa+rv, c->offset+rv, n-rv);
+ if(i <= 0)
+ break;
+ }
+ break;
+ case Qstruct:
+ hardident(dp);
+ if (n < 2*sizeof(ulong))
+ error(Ebadarg);
+ if (c->offset >= 2*sizeof(ulong))
+ return 0;
+ rv = 2*sizeof(ulong);
+ ul2user((uchar*)a, dp->cap);
+ ul2user((uchar*)a+sizeof(ulong), dp->bytes);
+ break;
+ default:
+ panic("hardread: bad qid");
+ }
+ return rv;
+}
+
+long
+hardwrite(Chan *c, void *a, long n)
+{
+ Drive *dp;
+ long rv, i;
+ uchar *aa = a;
+
+ rv = 0;
+ dp = &hard.d[c->qid.path & ~Qmask];
+ switch ((int)(c->qid.path & Qmask)) {
+ case Qdata:
+ for(rv = 0; rv < n; rv += i){
+ i = hardxfer(dp, Fwrite, aa+rv, c->offset+rv, n-rv);
+ if(i <= 0)
+ break;
+ }
+ break;
+ case Qstruct:
+ error(Eperm);
+ break;
+ default:
+ panic("hardwrite: bad qid");
+ }
+ return rv;
+}
+
+/*
+ * did an interrupt happen?
+ */
+static int
+interrupted(Drive *dp)
+{
+ return hard.intr;
+}
+
+/*
+ * get parameters from the drive
+ */
+hardident(Drive *dp)
+{
+ hard.intr = 0;
+ outb(Pdh, dp->dev<<4);
+ outb(Pcmd, Cident);
+}
+
+long
+hardxfer(Drive *dp, int cmd, void *va, long off, long len)
+{
+ errors("not implemented");
+}
+
M pc/fns.h => pc/fns.h +2 -4
@@ 5,13 5,11 @@ void a20enable(void);
void clock(Ureg*);
void clockinit(void);
void delay(int);
+void dmaend(int);
+long dmasetup(int, void*, long, int);
#define evenaddr(x) /* 386 doesn't care */
void fault386(Ureg*);
void faultinit(void);
-void floppyinit(void);
-void floppyintr(Ureg*);
-long floppyseek(int, long);
-long floppyread(int, void*, long);
#define flushvirt();
void fpsave(FPsave*);
void fprestore(FPsave*);
M pc/headland.c => pc/headland.c +32 -20
@@ 7,9 7,15 @@
/*
* headland chip set for the safari.
*/
+typedef struct DMAport DMAport;
+typedef struct DMA DMA;
+typedef struct DMAxfer DMAxfer;
enum
{
+ /*
+ * system control port
+ */
Head= 0x92, /* control port */
Reset= (1<<0), /* reset the 386 */
A20ena= (1<<1), /* enable address line 20 */
@@ 32,10 38,9 @@ enum
/*
* state of a dma transfer
*/
-typedef struct DMAxfer DMAxfer;
struct DMAxfer
{
- Page pg; /* page used by dma */
+ Page *pg; /* page used by dma */
void *va; /* virtual address destination/src */
long len; /* bytes to be transferred */
int isread;
@@ 45,7 50,6 @@ struct DMAxfer
* the dma controllers. the first half of this structure specifies
* the I/O ports used by the DMA controllers.
*/
-typedef struct DMAport DMAport;
struct DMAport
{
uchar addr[4]; /* current address (4 channels) */
@@ 63,7 67,6 @@ struct DMAport
Lock;
};
-typdef struct DMA DMA;
struct DMA
{
DMAport;
@@ 123,21 126,20 @@ dmasetup(int chan, void *va, long len, int isread)
uchar mode;
dp = &dma[(chan>>2)&1];
- chan &= 3;
+ chan = chan & 3;
xp = &dp->x[chan];
/*
- * if this isn't kernel memory, we can't count on it being
- * there during the DMA. Allocate a page for the DMA.
+ * if this isn't kernel memory (or crossing 64k boundary),
+ * allocate a page for the DMA.
*/
- if(isphys(va)){
- pa = va & ~KZERO;
- } else {
+ pa = ((ulong)va) & ~KZERO;
+ if(!isphys(va) || (pa&0xFFFF0000)!=((pa+len)&0xFFFF0000)){
xp->pg = newpage(1, 0, 0);
if(len > BY2PG)
len = BY2PG;
if(!isread)
- memmove(KZERO|xp->pg->pa, a, len);
+ memmove((void*)(KZERO|xp->pg->pa), va, len);
xp->va = va;
xp->len = len;
xp->isread = isread;
@@ 151,15 153,15 @@ dmasetup(int chan, void *va, long len, int isread)
outb(dp->cbp, 0); /* set count & address to their first byte */
mode = (isread ? 0x44 : 0x48) | chan;
outb(dp->mode, mode); /* single mode dma (give CPU a chance at mem) */
- outb(dp->addr, pa); /* set address */
- outb(dp->addr, pa>>8);
- outb(dp->page, pa>>16);
- outb(dp->count, len-1); /* set count */
- outb(dp->count, (len-1)>>8);
+ outb(dp->addr[chan], pa); /* set address */
+ outb(dp->addr[chan], pa>>8);
+ outb(dp->page[chan], pa>>16);
+ outb(dp->count[chan], len-1); /* set count */
+ outb(dp->count[chan], (len-1)>>8);
outb(dp->sbm, chan); /* enable the channel */
unlock(dp);
- return n;
+ return len;
}
/*
@@ 178,13 180,23 @@ dmaend(int chan)
uchar mode;
dp = &dma[(chan>>2)&1];
- chan &= 3;
- outb(dp->sbm, 4|chan); /* disable the channel */
+ chan = chan & 3;
+
+ /*
+ * disable the channel
+ */
+ lock(dp);
+ outb(dp->sbm, 4|chan);
+ unlock(dp);
+
xp = &dp->x[chan];
if(xp->pg == 0)
return;
- memmove(a, KZERO|xp->pg->pa, xp->len);
+ /*
+ * copy out of temporary page
+ */
+ memmove(xp->va, (void*)(KZERO|xp->pg->pa), xp->len);
putpage(xp->pg);
xp->pg = 0;
}
M pc/main.c => pc/main.c +0 -35
@@ 265,38 265,3 @@ void
lights(int val)
{
}
-
-/*
- * headland hip set for the safari.
- *
- * serious magic!!!
- */
-
-enum
-{
- Head= 0x92, /* control port */
- Reset= (1<<0), /* reset the 386 */
- A20ena= (1<<1), /* enable address line 20 */
-};
-
-/*
- * enable address bit 20
- */
-void
-a20enable(void)
-{
- outb(Head, A20ena);
-}
-
-/*
- * reset the chip
- */
-void
-exit(void)
-{
- int i;
-
- u = 0;
- print("exiting\n");
- outb(Head, Reset);
-}
M pc/trap.c => pc/trap.c +4 -5
@@ 251,6 251,7 @@ syscall(Ureg *ur)
sp = ur->usp;
u->nerrlab = 0;
ret = -1;
+ spllo();
if(!waserror()){
if(ax >= sizeof systab/BY2WD){
pprint("bad sys call number %d pc %lux\n", ax, ur->pc);
@@ 270,9 271,9 @@ syscall(Ureg *ur)
}
u->p->insyscall = 0;
ur->ax = ret;
- if(ax == NOTED)
+ if(ax == NOTED){
noted(ur, *(ulong*)(sp+BY2WD));
- else if(u->nnote && ax!=FORK){
+ } else if(u->nnote && ax!=FORK){
notify(ur);
}
return ret;
@@ 346,7 347,7 @@ noted(Ureg *ur, ulong arg0)
validaddr(nur->pc, 1, 0);
validaddr(nur->usp, BY2WD, 0);
if(nur->cs!=u->svcs || nur->ss!=u->svss
- || (nur->flags&0xff)!=(u->svflags&0xff)){
+ || (nur->flags&0xff00)!=(u->svflags&0xff00)){
pprint("bad noted ureg cs %ux ss %ux flags %ux\n", nur->cs, nur->ss,
nur->flags);
pexit("Suicide", 0);
@@ 359,10 360,8 @@ noted(Ureg *ur, ulong arg0)
u->notified = 0;
nur->flags = (u->svflags&0xffffff00) | (ur->flags&0xff);
memmove(ur, u->ureg, sizeof(Ureg));
-/* ur->ax = -1; /* return error from the interrupted syscall */
switch(arg0){
case NCONT:
- splhi();
unlock(&u->p->debug);
return;
M port/page.c => port/page.c +70 -40
@@ 51,31 51,50 @@ unlockpage(Page *p)
}
/*
- * Called to allocate permanent data structures, before calling pageinit().
+ * Called to allocate permanent data structures, before calling pageinit().
+ * We assume all of text+data+bss is in the first memory bank.
*/
void*
ialloc(ulong n, int align)
{
ulong p;
+ ulong *ap;
if(palloc.active && n!=0)
print("ialloc bad\n");
- if(palloc.addr == 0)
- palloc.addr = ((ulong)&end)&~KZERO;
- if(align)
- palloc.addr = PGROUND(palloc.addr);
- if(palloc.addr+n > conf.base0 + conf.npage0*BY2PG)
- palloc.addr = conf.base1;
+ if(palloc.addr0 == 0){
+ palloc.addr0 = ((ulong)&end)&~KZERO;
+ palloc.addr1 = conf.base1;
+ }
- memset((void*)(palloc.addr|KZERO), 0, n);
- p = palloc.addr;
- palloc.addr += n;
- if(align)
- palloc.addr = PGROUND(palloc.addr);
+ /*
+ * try first bank
+ */
+ p = align ? PGROUND(palloc.addr0) : palloc.addr0;
+ if(p+n > conf.base0 + (conf.npage0<<PGSHIFT)){
+ /*
+ * no room in first bank, try second bank
+ */
+ if(conf.npage1 <= 0)
+ panic("keep bill joy away 1");
+ p = align ? PGROUND(palloc.addr1) : palloc.addr1;
+ ap = &palloc.addr1;
+ } else
+ ap = &palloc.addr0;
+
+ if(p >= conf.maxialloc)
+ panic("keep bill joy away 2");
- if(palloc.addr >= conf.maxialloc)
- panic("keep bill joy away");
+ /*
+ * zero it
+ */
+ memset((void*)(p|KZERO), 0, n);
+
+ /*
+ * don't put anything else into a page aligned ialloc
+ */
+ *ap = align ? PGROUND(p+n) : (p+n);
return (void*)(p|KZERO);
}
@@ 83,44 102,55 @@ ialloc(ulong n, int align)
void
pageinit(void)
{
- ulong pa, nb, ppn;
+ ulong np, addr, lim;
ulong i, vmem, pmem;
Page *p;
- palloc.active = 1;
-
- nb = (conf.npage<<PGSHIFT) - palloc.addr;
- nb -= ((nb+(BY2PG-1))>>PGSHIFT)*sizeof(Page); /* safe overestimate */
- nb &= ~(BY2PG-1);
- pa = (conf.npage<<PGSHIFT) - nb; /* physical addr of first free page */
- ppn = pa >> 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
+ * calculate an upper bound to the number of pages structures
+ * we'll need (np).
*/
- palloc.minppn = ppn;
- palloc.addr = ppn<<PGSHIFT;
+ np = (conf.npage0<<PGSHIFT) - (palloc.addr0 - conf.base0);
+ np += (conf.npage1<<PGSHIFT) - (palloc.addr1 - conf.base1);
+ np = np>>PGSHIFT;
- palloc.head = &palloc.page[ppn];
- palloc.tail = &palloc.page[conf.npage-1];
- memset(palloc.head, 0, (conf.npage-ppn)*sizeof(Page));
-
- pmem = ((conf.npage-ppn)*BY2PG)/1024;
- vmem = pmem + ((conf.nswap)*BY2PG)/1024;
- palloc.user = conf.npage-ppn;
- print("%lud free pages, %dK bytes, swap %dK bytes\n", palloc.user, pmem, vmem);
+ /*
+ * allocate Page structs (no more ialloc's allowed after this).
+ * np is useless after this ialloc since we've just eaten up
+ * some pages for the Page structures.
+ */
+ palloc.head = ialloc(np*sizeof(Page), 0);
+ palloc.active = 1;
- for(p=palloc.head; p<=palloc.tail; p++,ppn++){
+ /*
+ * for each page in each bank, point a page structure to
+ * the page and chain it into the free list
+ */
+ p = palloc.head;
+ addr = palloc.addr0 = PGROUND(palloc.addr0);
+ lim = conf.base0 + (conf.npage0<<PGSHIFT);
+ for(; addr < lim; addr += BY2PG){
p->next = p+1;
p->prev = p-1;
- if(ppn < conf.npage0)
- p->pa = conf.base0+(ppn<<PGSHIFT);
- else
- p->pa = conf.base1+((ppn-conf.npage0)<<PGSHIFT);
- palloc.freecount++;
+ p->pa = addr;
+ p++;
}
+ addr = palloc.addr1 = PGROUND(palloc.addr1);
+ lim = conf.base1 + (conf.npage1<<PGSHIFT);
+ for(; addr < lim; addr += BY2PG){
+ p->next = p+1;
+ p->prev = p-1;
+ p->pa = addr;
+ p++;
+ }
+ palloc.tail = p - 1;
palloc.head->prev = 0;
palloc.tail->next = 0;
+
+ palloc.user = palloc.freecount = p - palloc.head;
+ pmem = palloc.user*BY2PG/1024;
+ vmem = pmem + ((conf.nswap)*BY2PG)/1024;
+ print("%lud free pages, %dK bytes, swap %dK bytes\n", palloc.user, pmem, vmem);
}
Page*
M port/portdat.h => port/portdat.h +2 -3
@@ 388,10 388,9 @@ struct Fgrp
struct Palloc
{
Lock;
- ulong addr;
+ ulong addr0; /* next available ialloc addr in bank 0 */
+ ulong addr1; /* next available ialloc addr in bank 1 */
int active;
- Page *page; /* base of Page structures */
- ulong minppn; /* index of first usable page */
Page *head; /* most recently used */
Page *tail; /* least recently used */
ulong freecount; /* how many pages on free list now */
M power/lock.c => power/lock.c +18 -14
@@ 115,15 115,17 @@ lock(Lock *l)
sbsem = l->sbsem;
if(sbsem == 0){
lock(&semalloc.lock);
- if(semalloc.nsem == SEMPERPG){
- semalloc.nsem = 0;
- semalloc.nextsem = lkpgalloc();
+ if(l->sbsem == 0){
+ if(semalloc.nsem == SEMPERPG){
+ semalloc.nsem = 0;
+ semalloc.nextsem = lkpgalloc();
+ }
+ l->sbsem = semalloc.nextsem;
+ semalloc.nextsem++;
+ semalloc.nsem++;
+ unlock(l); /* put sem in known state */
}
- l->sbsem = semalloc.nextsem;
- semalloc.nextsem++;
- semalloc.nsem++;
unlock(&semalloc.lock);
- unlock(l); /* put sem in known state */
sbsem = l->sbsem;
}
/*
@@ 151,15 153,17 @@ canlock(Lock *l)
sbsem = l->sbsem;
if(sbsem == 0){
lock(&semalloc.lock);
- if(semalloc.nsem == SEMPERPG){
- semalloc.nsem = 0;
- semalloc.nextsem = lkpgalloc();
+ if(l->sbsem == 0){
+ if(semalloc.nsem == SEMPERPG){
+ semalloc.nsem = 0;
+ semalloc.nextsem = lkpgalloc();
+ }
+ l->sbsem = semalloc.nextsem;
+ semalloc.nextsem++;
+ semalloc.nsem++;
+ unlock(l); /* put sem in known state */
}
- l->sbsem = semalloc.nextsem;
- semalloc.nextsem++;
- semalloc.nsem++;
unlock(&semalloc.lock);
- unlock(l); /* put sem in known state */
sbsem = l->sbsem;
}
if(*sbsem & 1)
M power/segment.h => power/segment.h +3 -4
@@ 12,9 12,8 @@ struct Physseg
Page *(*pgalloc)(ulong); /* Allocation if we need it */
void (*pgfree)(Page*);
}physseg[] = {
- { SG_PHYSICAL, "lock", 0, 1024*BY2PG, &lkpage, &lkpgfree },
- { SG_SHARED, "shared", 0, SEGMAXSIZE, &snewpage, &putpage },
- { SG_PHYSICAL, "kmem", KZERO, SEGMAXSIZE, 0, 0 },
- { SG_BSS, "memory", 0, SEGMAXSIZE, &snewpage, &putpage },
+ { SG_PHYSICAL, "lock", 0, 1024*BY2PG, lkpage, lkpgfree },
+ { SG_SHARED, "shared", 0, SEGMAXSIZE, snewpage, putpage },
+ { SG_BSS, "memory", 0, SEGMAXSIZE, snewpage, putpage },
{ 0, 0, 0, 0, 0, 0 },
};