~kris/9p

9hist

7428ad83a37707fcfa44bb341902eb466bdf53fb — David du Colombier 35 years ago 23038bb
Plan 9 from Bell Labs 1991-08-01
11 files changed, 670 insertions(+), 44 deletions(-)

M pc/clock.c
M pc/dat.h
A pc/devuart.c
M pc/fault386.c
M pc/io.h
M pc/kbd.c
M pc/main.c
M pc/mmu.c
M pc/trap.c
M pc/vga.c
M port/page.c
M pc/clock.c => pc/clock.c +3 -4
@@ 69,14 69,13 @@ clock(Ureg *ur)
		if (p->state==Running)
			p->time[p->insyscall]++;
	}
/*
	if(u && (ur->flags&IFLAG) && p && p->state==Running){

/*	if(u && p && p->state==Running){
		if(anyready()){
			if(p->hasspin)
				p->hasspin = 0;
			else
				sched();
		}
	}
/**/
	}/**/
}

M pc/dat.h => pc/dat.h +2 -0
@@ 189,3 189,5 @@ struct

extern Mach	*m;
extern User	*u;

extern int	flipD[];	/* for flipping bitblt destination polarity */

A pc/devuart.c => pc/devuart.c +629 -0
@@ 0,0 1,629 @@
#include	"u.h"
#include	"lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"io.h"
#include	"errno.h"

#include	"devtab.h"

/*
 *  Driver for an NS16450 serial port
 */
enum
{
	/*
	 *  register numbers
	 */
	Data=	0,		/* xmit/rcv buffer */
	Iena=	1,		/* interrupt enable */
	 Ircv=	(1<<0),		/*  interrupt on receive */
	 Ixmt=	(1<<1),		/*  interrupt on xmit */
	Istat=	2,		/* interrupt flag */
	Format=	3,		/* byte format */
	 Bits8=	(3<<0),		/*  8 bits/byte */
	 Stop2=	(1<<2),		/*  2 stop bits */
	 Pena=	(1<<3),		/*  generate parity */
	 Peven=	(1<<4),		/*  even parity */
	 Pforce=(1<<5),		/*  force parity */
	 Break=	(1<<6),		/*  generate a break */
	 Dra=	(1<<7),		/*  address the divisor */
	Mctl=	4,		/* modem control */
	 Dtr=	(1<<0),		/*  data terminal ready */
	 Rts=	(1<<1),		/*  request to send */
	 Ri=	(1<<2),		/*  ring */
	 Dcd=	(1<<3),		/*  carrier */
	 Loop=	(1<<4),		/*  loop bask */
	Lstat=	5,		/* line status */
	 Inready=(1<<0),	/*  receive buffer full */
	 Outbusy=(1<<5),	/*  output buffer full */
	Mstat=	6,		/* modem status */
	Scratch=7,		/* scratchpad */
	Dlsb=	0,		/* divisor lsb */
	Dmsb=	1,		/* divisor msb */
};

typedef struct Uart	Uart;
struct Uart
{
	QLock;
	int	port;
	ushort	sticky[16];	/* sticky write register values */
	int	printing;	/* true if printing */

	/* console interface */
	int	nostream;	/* can't use the stream interface */
	IOQ	*iq;		/* input character queue */
	IOQ	*oq;		/* output character queue */

	/* stream interface */
	Queue	*wq;		/* write queue */
	Rendez	r;		/* kproc waiting for input */
	Alarm	*a;		/* alarm for waking the kernel process */
	int	delay;		/* between character input and waking kproc */
 	int	kstarted;	/* kproc started */
	uchar	delim[256/8];	/* characters that act as delimiters */
};

Uart uart[2];

#define UartFREQ 1846200

#define uartwrreg(u,r,v)	outb(u->port + r, u->sticky[r] | v)
#define uartrdreg(u,r)		inb(u->port + r)

void	uartintr(Uart*);
void	uartintr0(Ureg*);
void	uartintr1(Ureg*);
void	uartsetup(void);

/*
 *  set the baud rate by calculating and setting the baudrate
 *  generator constant.  This will work with fairly non-standard
 *  baud rates.
 */
void
uartsetbaud(Uart *up, int rate)
{
	ulong brconst;

	brconst = (UartFREQ+8*rate-1)/16*rate;

	uartwrreg(up, Format, Dra);
	uartwrreg(up, Dmsb, (brconst>>8) & 0xff);
	uartwrreg(up, Dlsb, brconst & 0xff);
	uartwrreg(up, Format, 0);
}

/*
 *  toggle DTR
 */
void
uartdtr(Uart *up, int n)
{
	if(n)
		up->sticky[Mctl] |= Dtr;
	else
		up->sticky[Mctl] &= ~Dtr;
	uartwrreg(up, Mctl, 0);
}

/*
 *  toggle RTS
 */
void
uartrts(Uart *up, int n)
{
	if(n)
		up->sticky[Mctl] |= Rts;
	else
		up->sticky[Mctl] &= ~Rts;
	uartwrreg(up, Mctl, 0);
}

/*
 *  send break
 */
void
uartbreak(Uart *up, int ms)
{
	uartwrreg(up, Format, Break);
	tsleep(&u->p->sleep, return0, 0, ms);
	uartwrreg(up, Format, 0);
}

/*
 *  default is 9600 baud, 1 stop bit, 8 bit chars, no interrupts,
 *  transmit and receive enabled, interrupts disabled.
 */
void
uartsetup(void)
{
	Uart *up;
	static int already;

	if(already)
		return;
	already = 1;

	/*
	 *  get port addresses
	 */
	uart[0].port = 0x3F8;
	uart[1].port = 0x2F8;
	setvec(Uart0vec, uartintr0);
	setvec(Uart1vec, uartintr1);

	for(up = uart; up < &uart[2]; up++){
		memset(up->sticky, 0, sizeof(up->sticky));

		/*
		 *  set rate to 9600 baud.
		 *  8 bits/character.
		 *  1 stop bit.
		 */
		uartsetbaud(up, 9600);
		up->sticky[Format] = Bits8;
		uartwrreg(up, Format, 0);
	}
}

/*
 *  Queue n characters for output; if queue is full, we lose characters.
 *  Get the output going if it isn't already.
 */
void
uartputs(IOQ *cq, char *s, int n)
{
	Uart *up = cq->ptr;
	int st, ch, x;

	x = splhi();
	lock(cq);
	puts(cq, s, n);
	if(up->printing == 0){
		ch = getc(cq);
print("<start %2.2ux>", ch);/**/
		if(ch >= 0){
			up->printing = 1;
			while(uartrdreg(up, Lstat) & Outbusy)
				;
			outb(up->port + Data, ch);
		}
	}
	unlock(cq);
	splx(x);
}

/*
 *  a uart interrupt (a damn lot of work for one character)
 */
void
uartintr(Uart *up)
{
	int s;
	int ch;
	IOQ *cq;

	switch(uartrdreg(up, Istat)){
	case 3:
		/*
		 *  get any input characters
		 */
		cq = up->iq;
		while(uartrdreg(up, Lstat) & Inready){
			ch = uartrdreg(up, Data) & 0xff;
			if(cq->putc)
				(*cq->putc)(cq, ch);
			else {
				putc(cq, ch);
				if(up->delim[ch/8] & (1<<(ch&7)) )
					wakeup(&cq->r);
			}
		}
		break;
	case 5:
		/*
		 *  send next output character
		 */
		if((s & Outbusy)==0){
			cq = up->oq;
			lock(cq);
			ch = getc(cq);
			if(ch < 0){
				up->printing = 0;
				wakeup(&cq->r);
			}else
				outb(up->port + Data, ch);
			unlock(cq);
		}
		break;
	}
}
void
uartintr0(Ureg *ur)
{
	uartintr(&uart[0]);
}
void
uartintr1(Ureg *ur)
{
	uartintr(&uart[1]);
}

/*
 *  turn on a port's interrupts.  set DTR and RTS
 */
void
uartenable(Uart *up)
{
	/*
	 *  set up i/o routines
	 */
	if(up->oq){
		up->oq->puts = uartputs;
		up->oq->ptr = up;
		up->sticky[Iena] |= Ixmt;
	}
	if(up->iq){
		up->iq->ptr = up;
		up->sticky[Iena] |= Ircv;
	}

	/*
 	 *  turn on interrupts
	 */
	uartwrreg(up, Iena, 0);

	/*
	 *  turn on DTR and RTS
	 */
	uartdtr(up, 1);
	uartrts(up, 1);
}

/*
 *  set up an uart port as something other than a stream
 */
void
uartspecial(int port, IOQ *oq, IOQ *iq, int baud)
{
	Uart *up = &uart[port];

	uartsetup();
	up->nostream = 1;
	up->oq = oq;
	up->iq = iq;
	uartenable(up);
	uartsetbaud(up, baud);

	if(iq){
		/*
		 *  Stupid HACK to undo a stupid hack
		 */ 
		if(iq == &kbdq)
			kbdq.putc = kbdcr2nl;
	}
}

static void	uarttimer(Alarm*);
static int	uartputc(IOQ *, int);
static void	uartstopen(Queue*, Stream*);
static void	uartstclose(Queue*);
static void	uartoput(Queue*, Block*);
static void	uartkproc(void *);
Qinfo uartinfo =
{
	nullput,
	uartoput,
	uartstopen,
	uartstclose,
	"uart"
};

/*
 *  create a helper process per port
 */
static void
uarttimer(Alarm *a)
{
	Uart *up = a->arg;

	cancel(a);
	up->a = 0;
	wakeup(&up->iq->r);
}

static int
uartputc(IOQ *cq, int ch)
{
	Uart *up = cq->ptr; int r;

	r = putc(cq, ch);

	/*
	 *  pass upstream within up->delay milliseconds
	 */
	if(up->a==0){
		if(up->delay == 0)
			wakeup(&cq->r);
		else
			up->a = alarm(up->delay, uarttimer, up);
	}
	return r;
}

static void
uartstopen(Queue *q, Stream *s)
{
	Uart *up;
	char name[NAMELEN];

	kprint("uartstopen: q=0x%ux, inuse=%d, type=%d, dev=%d, id=%d\n",
		q, s->inuse, s->type, s->dev, s->id);
	up = &uart[s->id];
	qlock(up);
	up->wq = WR(q);
	WR(q)->ptr = up;
	RD(q)->ptr = up;
	up->delay = 64;
	up->iq->putc = uartputc;
	qunlock(up);

	/* start with all characters as delimiters */
	memset(up->delim, 1, sizeof(up->delim));
	
	if(up->kstarted == 0){
		up->kstarted = 1;
		sprint(name, "uart%d", s->id);
		kproc(name, uartkproc, up);
	}
}

static void
uartstclose(Queue *q)
{
	Uart *up = q->ptr;

	qlock(up);
	kprint("uartstclose: q=0x%ux, id=%d\n", q, up-uart);
	up->wq = 0;
	up->iq->putc = 0;
	WR(q)->ptr = 0;
	RD(q)->ptr = 0;
	qunlock(up);
}

static void
uartoput(Queue *q, Block *bp)
{
	Uart *up = q->ptr;
	IOQ *cq;
	int n, m;

	if(up == 0){
		freeb(bp);
		return;
	}
	cq = up->oq;
	if(waserror()){
		freeb(bp);
		nexterror();
	}
	if(bp->type == M_CTL){
		while (cangetc(cq))	/* let output drain */
			sleep(&cq->r, cangetc, cq);
		n = strtoul((char *)(bp->rptr+1), 0, 0);
		switch(*bp->rptr){
		case 'B':
		case 'b':
			uartsetbaud(up, n);
			break;
		case 'D':
		case 'd':
			uartdtr(up, n);
			break;
		case 'K':
		case 'k':
			uartbreak(up, n);
			break;
		case 'R':
		case 'r':
			uartrts(up, n);
			break;
		case 'W':
		case 'w':
			if(n>=0 && n<1000)
				up->delay = n;
			break;
		}
	}else while((m = BLEN(bp)) > 0){
		while ((n = canputc(cq)) == 0){
print("uartoput: sleeping\n");
			sleep(&cq->r, canputc, cq);
		}
		if(n > m)
			n = m;
		(*cq->puts)(cq, bp->rptr, n);
		bp->rptr += n;
	}
	freeb(bp);
	poperror();
}

/*
 *  process to send bytes upstream for a port
 */
static void
uartkproc(void *a)
{
	Uart *up = a;
	IOQ *cq = up->iq;
	Block *bp;
	int n;

loop:
	while ((n = cangetc(cq)) == 0){
print("uart0 sleeping/n");
		sleep(&cq->r, cangetc, cq);
	}
	qlock(up);
	if(up->wq == 0){
		cq->out = cq->in;
	}else{
		bp = allocb(n);
		bp->flags |= S_DELIM;
		bp->wptr += gets(cq, bp->wptr, n);
		PUTNEXT(RD(up->wq), bp);
	}
	qunlock(up);
	goto loop;
}

enum{
	Qdir=		0,
	Qtty0=		STREAMQID(0, Sdataqid),
	Qtty0ctl=	STREAMQID(0, Sctlqid),
	Qtty1=		STREAMQID(1, Sdataqid),
	Qtty1ctl=	STREAMQID(1, Sctlqid),
};

Dirtab uartdir[]={
	"tty0",		{Qtty0},	0,		0666,
	"tty0ctl",	{Qtty0ctl},	0,		0666,
	"tty1",		{Qtty1},	0,		0666,
	"tty1ctl",	{Qtty1ctl},	0,		0666,
};

#define	NUart	(sizeof uartdir/sizeof(Dirtab))

/*
 *  allocate the queues if no one else has
 */
void
uartreset(void)
{
	Uart *up;

	uartsetup();
	for(up = uart; up < &uart[2]; up++){
		if(up->nostream)
			continue;
		up->iq = ialloc(sizeof(IOQ), 0);
		initq(up->iq);
		up->oq = ialloc(sizeof(IOQ), 0);
		initq(up->oq);
		uartenable(up);
	}
}

void
uartinit(void)
{
}

Chan*
uartattach(char *upec)
{
	return devattach('t', upec);
}

Chan*
uartclone(Chan *c, Chan *nc)
{
	return devclone(c, nc);
}

int
uartwalk(Chan *c, char *name)
{
	return devwalk(c, name, uartdir, NUart, devgen);
}

void
uartstat(Chan *c, char *dp)
{
	switch(c->qid.path){
	case Qtty0:
		streamstat(c, dp, "tty0");
		break;
	case Qtty1:
		streamstat(c, dp, "tty1");
		break;
	default:
		devstat(c, dp, uartdir, NUart, devgen);
		break;
	}
}

Chan*
uartopen(Chan *c, int omode)
{
	Uart *up;

	switch(c->qid.path){
	case Qtty0:
	case Qtty0ctl:
		up = &uart[0];
		break;
	case Qtty1:
	case Qtty1ctl:
		up = &uart[1];
		break;
	default:
		up = 0;
		break;
	}

	if(up && up->nostream)
		errors("in use");

	if((c->qid.path & CHDIR) == 0)
		streamopen(c, &uartinfo);
	return devopen(c, omode, uartdir, NUart, devgen);
}

void
uartcreate(Chan *c, char *name, int omode, ulong perm)
{
	error(Eperm);
}

void
uartclose(Chan *c)
{
	if(c->stream)
		streamclose(c);
}

long
uartread(Chan *c, void *buf, long n, ulong offset)
{
	switch(c->qid.path&~CHDIR){
	case Qdir:
		return devdirread(c, buf, n, uartdir, NUart, devgen);
	case Qtty1ctl:
	case Qtty0ctl:
		return 0;
	}
	return streamread(c, buf, n);
}

long
uartwrite(Chan *c, void *va, long n, ulong offset)
{
	return streamwrite(c, va, n, 0);
}

void
uartremove(Chan *c)
{
	error(Eperm);
}

void
uartwstat(Chan *c, char *dp)
{
	error(Eperm);
}

M pc/fault386.c => pc/fault386.c +1 -3
@@ 20,8 20,6 @@ fault386(Ureg *ur)
	insyscall = u->p->insyscall;
	u->p->insyscall = 1;
	addr = getcr2();
print("fault386 %lux ur %lux\n", addr, ur);
dumpregs(ur);
	if(faulting)
		panic("double fault\n");
	faulting = 1;


@@ 37,7 35,7 @@ dumpregs(ur);
		}
		u->p->state = MMUing;
		dumpregs(ur);
		panic("fault: 0x%lux", addr);
		panic("fault: 0x%lux 0x%lux", addr);
	}
	faulting = 0;
	u->p->insyscall = insyscall;

M pc/io.h => pc/io.h +2 -2
@@ 7,8 7,8 @@ enum
	Int0vec=	16,		/* first 8259 */
	 Clockvec=	Int0vec+0,	/*  clock interrupts */
	 Kbdvec=	Int0vec+1,	/*  keyboard interrupts */
	 ComBvec=	Int0vec+3,	/*  inerrupt from uart b */
	 ComAvec=	Int0vec+4,	/*  inerrupt from uart a */
	 Uart0vec=	Int0vec+3,	/*  inerrupt from uart b */
	 Uart1vec=	Int0vec+4,	/*  inerrupt from uart a */
	 Floppyvec=	Int0vec+6,	/*  floppy interrupts */
	Int1vec=	Int0vec+8,	/* second 8259 */
	 Mousevec=	Int1vec+4,	/*  mouse interrupt */

M pc/kbd.c => pc/kbd.c +1 -4
@@ 294,9 294,7 @@ kbdinit(void)
	mousecmd(0xF4, -1);

	/* resolution */
	mousecmd(0xE8, 0x03);
print("res set\n");
delay(5000);
/*	mousecmd(0xE8, 0x03); /**/
}

/*


@@ 333,7 331,6 @@ mymouseputc(int c)
		mouse.newbuttons = b[msg[0]&7];
		mouse.dx = msg[1];
		mouse.dy = -msg[2];
print("%d %d\n", mouse.dx, mouse.dy);
		mouse.track = 1;
		mouseclock();
	}

M pc/main.c => pc/main.c +3 -5
@@ 28,7 28,9 @@ main(void)
	grpinit();
	chaninit();
	alarminit();
print("chandevreset\n"); delay(1000);
	chandevreset();
print("streaminit\n"); delay(1000);
	streaminit();
	swapinit();
	pageinit();


@@ 65,7 67,6 @@ init0(void)
	u->p->state = Running;
	u->p->mach = m;

print("go low\n");
	spllo();

	/*


@@ 77,9 78,6 @@ print("go low\n");

	chandevinit();

print("going to user\n");
delay(1000);

	touser();
}



@@ 183,7 181,7 @@ confinit(void)
	conf.base1 = 1024*1024;

	conf.npage = conf.npage0 + conf.npage1;
	conf.maxialloc = (conf.npage0*BY2PG-PGROUND((ulong)&end));
	conf.maxialloc = 2*1024*1024;

	mul = 1;
	conf.nproc = 20 + 20*mul;

M pc/mmu.c => pc/mmu.c +5 -5
@@ 218,7 218,7 @@ putmmu(ulong va, ulong pa, Page *pg)
	Proc *p;
	int i = 0;

print("putmmu %lux %lux\n", va, pa); /**/
/*print("putmmu %lux %lux\n", va, pa); /**/
	if(u==0)
		panic("putmmu");
	p = u->p;


@@ 238,21 238,21 @@ print("putmmu %lux %lux\n", va, pa); /**/
	 *  if bottom level page table missing, allocate one
	 */
	pg = p->mmu[i];
print("toppt[%d] was %lux\n", topoff, toppt[topoff]);
/*print("toppt[%d] was %lux\n", topoff, toppt[topoff]);/**/
	if(pg == 0){
		pg = p->mmu[i] = newpage(1, 0, 0);
		p->mmue[i] = PPN(pg->pa) | PTEVALID | PTEUSER | PTEWRITE;
		toppt[topoff] = p->mmue[i];
print("toppt[%d] now %lux\n", topoff, toppt[topoff]);
/*print("toppt[%d] now %lux\n", topoff, toppt[topoff]);/**/
	}

	/*
	 *  fill in the bottom level page table
	 */
	pt = (ulong*)(p->mmu[i]->pa|KZERO);
print("%lux[%d] was %lux\n", pt, BTMOFF(va), pt[BTMOFF(va)]);
/*print("%lux[%d] was %lux\n", pt, BTMOFF(va), pt[BTMOFF(va)]);/**/
	pt[BTMOFF(va)] = pa | PTEUSER;
print("%lux[%d] now %lux\n", pt, BTMOFF(va), pt[BTMOFF(va)]);
/*print("%lux[%d] now %lux\n", pt, BTMOFF(va), pt[BTMOFF(va)]);/**/

	/* flush cached mmu entries */
	putcr3(((ulong)toppt)&~KZERO);

M pc/trap.c => pc/trap.c +8 -7
@@ 177,13 177,9 @@ trap(Ureg *ur)
		panic("bad trap type %d %lux\n", v, ur->pc);

	/*
	 *  call the trap routine
	 */
	(*ivec[v])(ur);

	/*
	 *  tell the 8259 that we're done with the
	 *  highest level interrupt
	 *  highest level interrupt (interrupts are still
	 *  off at this point)
	 */
	c = v&~0x7;
	if(c==Int0vec || c==Int1vec){


@@ 191,6 187,11 @@ trap(Ureg *ur)
		if(c == Int1vec)
			outb(Int1ctl, EOI);
	}

	/*
	 *  call the trap routine
	 */
	(*ivec[v])(ur);
}

/*


@@ 268,10 269,10 @@ syscall(Ureg *ur)
		panic("error stack");
	}
	u->p->insyscall = 0;
	ur->ax = ret;
	if(ax == NOTED)
		noted(ur, *(ulong*)(sp+BY2WD));
	else if(u->nnote && ax!=FORK){
		ur->ax = ret;
		notify(ur);
	}
	return ret;

M pc/vga.c => pc/vga.c +13 -14
@@ 167,26 167,25 @@ screeninit(void)
	srout(Smmask, 0x0f);	/* enable all 4 color planes for writing */

	/*
	 *  swizzle the font longs.
	 *  we do it here since the font is initialized with big endian longs.
	 */
	defont = &defont0;
	l = defont->bits->base;
	for(i = defont->bits->width*Dy(defont->bits->r); i > 0; i--, l++)
		*l = (*l<<24) | ((*l>>8)&0x0000ff00) | ((*l<<8)&0x00ff0000) | (*l>>24);

	/*
	 *  zero out display
	 */
	defont = &defont0;	/* save space; let bitblt do the conversion work */
	gbitblt(&gscreen, Pt(0, 0), &gscreen, gscreen.r, 0); /**/
	gbitblt(&gscreen, Pt(0, 0), &gscreen, gscreen.r, flipD[0]);

	/*
	 *  stick print at the top
	 *  start printing at the top of screen
	 */
	out.pos.x = MINX;
	out.pos.y = 0;
	out.bwid = defont0.info[' '].width;

	/*
	 *  swizzle the damn font longs.
	 *  we do it here since the font is in a machine independent (i.e.
	 *  made for the 68020) format.
	 */
	l = defont->bits->base;
	for(i = defont->bits->width*Dy(defont->bits->r); i > 0; i--, l++)
		*l = (*l<<24) | ((*l>>8)&0x0000ff00) | ((*l<<8)&0x00ff0000) | (*l>>24);
}

void


@@ 201,7 200,7 @@ screenputc(int c)
		if(out.pos.y > gscreen.r.max.y-defont0.height)
			out.pos.y = gscreen.r.min.y;
		gbitblt(&gscreen, Pt(0, out.pos.y), &gscreen,
		    Rect(0, out.pos.y, gscreen.r.max.x, out.pos.y+2*defont0.height), 0);
		    Rect(0, out.pos.y, gscreen.r.max.x, out.pos.y+2*defont0.height), flipD[0]);
	}else if(c == '\t'){
		out.pos.x += (8-((out.pos.x-MINX)/out.bwid&7))*out.bwid;
		if(out.pos.x >= gscreen.r.max.x)


@@ 217,7 216,7 @@ screenputc(int c)
			screenputc('\n');
		buf[0] = c&0x7F;
		buf[1] = 0;
		out.pos = gstring(&gscreen, out.pos, defont, buf, S);
		out.pos = gstring(&gscreen, out.pos, defont, buf, flipD[S]);
	}
}


M port/page.c => port/page.c +3 -0
@@ 65,6 65,9 @@ ialloc(ulong n, int align)
	if(align)
		palloc.addr = PGROUND(palloc.addr);

	if(palloc.addr+n > conf.base0 + conf.npage0*BY2PG)
		palloc.addr = conf.base1;

	memset((void*)(palloc.addr|KZERO), 0, n);
	p = palloc.addr;
	palloc.addr += n;