~kris/9p

9hist

0840ca4ab4184994bf3495c6ae74cd4d52464800 — David du Colombier 35 years ago 7428ad8
Plan 9 from Bell Labs 1991-08-02
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 	},
};