~kris/9p

9hist

0ce142868970528ddfa6f5e0d90abb5a43456db5 — David du Colombier 27 years ago a49cf8b
Plan 9 from Bell Labs 1999-01-23
6 files changed, 526 insertions(+), 106 deletions(-)

M mpc/clock.c
M mpc/devuart.c
M mpc/l.s
M mpc/main.c
M mpc/mem.h
M mpc/trap.c
M mpc/clock.c => mpc/clock.c +6 -8
@@ 70,7 70,7 @@ clockinit(void)
{
	long x, est;

	est = m->cpuhz/1000;	/* initial estimate */
	est = m->clockgen/1000;	/* initial estimate */
	m->delayloop = est;
	do {
		x = gettbl();


@@ 105,9 105,13 @@ clockintr(Ureg *ur)
	}
	putdec(clkreload-v);

	// keep alive for watchdog
	m->iomem->swsr = 0x556c;
	m->iomem->swsr = 0xaa39;
	
	m->ticks++;
//	if(m->ticks%MS2TK(1000) == 0)
//		m->bcsr[4] ^= DisableLamp;
//		*(uchar*)(NIMMEM+0x2200) = (m->ticks/MS2TK(1000))&2;

	if(up)
		up->pc = ur->pc;


@@ 131,12 135,6 @@ clockintr(Ureg *ur)
}

void
clockcheck(void)
{
	/* called by ../port/taslock.c: reset watchdog here, if it's enabled */
}

void
clkprint(void)
{
	print("clkr=%ld clkvv=%ld clkhigh=%lud\n", clkreload, clkvv, clkhigh);

M mpc/devuart.c => mpc/devuart.c +9 -9
@@ 297,7 297,7 @@ smcsetup(Uart *up)
	smc->smcm = BSY|RXB|TXB;	/* enable all possible interrupts */
	up->smc = smc;
	smc->smcmr = ((1+8+1-1)<<11)|(2<<4);	/* 8-bit, 1 stop, no parity; UART mode */
//	intrenable(VectorCPIC+4, smcuintr, up, BUSUNKNOWN);
	intrenable(VectorCPIC+4, smcuintr, up, BUSUNKNOWN);
	smc->smcmr |= 3;	/* enable rx/tx */
}



@@ 763,10 763,12 @@ static void
txstart(Uart *p)
{
	Block *b;
	int n, flags;
	int n, flags, s;


	if(!p->cts || p->blocked || p->txb->status & BDReady)
		return;

	if((b = p->outb) == nil){
		if((b = qget(p->oq)) == nil)
			return;


@@ 785,8 787,8 @@ txstart(Uart *p)
		}
	}
	n = BLEN(b);
	if(n <= 0)
		print("txstart: 0\n");
//	if(n <= 0)
//		print("txstart: 0\n");
	if(p->bpc > 8){
		/* half-word alignment and length if chars are long */
		if(PADDR(b->rp)&1){	/* must be even if chars are long */


@@ 810,11 812,8 @@ txstart(Uart *p)
	p->txb->addr = PADDR(b->rp);
	p->txb->length = n;
	eieio();
	p->txb->status = (p->txb->status & BDWrap) | flags | BDReady/*|BDInt */;
	p->txb->status = (p->txb->status & BDWrap) | flags | BDReady | BDInt;
	eieio();

	while(p->txb->status & BDReady)
		flash();
}

/*


@@ 991,11 990,11 @@ uartintr(Uart *p, int events)
	int dokick;
	BD *bd;
	Block *b;

	if(events & BSY)
		p->overrun++;
	p->interrupts++;
	dokick = 0;
/*
	while(p->rxb != nil && ((bd = &p->rxb[p->rdrx])->status & BDEmpty) == 0){
		if(p->mode)
			framedinput(p, bd);


@@ 1006,6 1005,7 @@ uartintr(Uart *p, int events)
		bd->status = (bd->status & BDWrap) | BDEmpty|BDInt;
		p->rdrx ^= 1;
	}
*/
	if((bd = p->txb) != nil){
		if((bd->status & BDReady) == 0){
			ilock(&p->plock);

M mpc/l.s => mpc/l.s +5 -29
@@ 131,6 131,9 @@ clrmach:
	CMP	R3, R4
	BNE	clrmach

	MOVW	R0, R(USER)
	MOVW	R0, 0(R(MACH))

	MOVW	$edata(SB), R3
	MOVW	$end(SB), R4
	ADD	$4, R4


@@ 295,10 298,10 @@ TEXT	saveureg(SB), $-4
	MOVW	$0, R0	/* compiler/linker expect R0 to be zero */

	MOVW	MSR, R5
	OR	$(MSR_IR|MSR_DR), R5	/* enable MMU */
/*	OR	$(MSR_IR|MSR_DR), R5	/* enable MMU */
	MOVW	R5, SPR(SRR1)
	MOVW	LR, R31
	OR	$KZERO, R31	/* return PC in KSEG0 */
/*	OR	$KZERO, R31	/* return PC in KSEG0 */
	MOVW	R31, SPR(SRR0)
	SYNC
	ISYNC


@@ 527,22 530,9 @@ TEXT	trapvec(SB), $-4
traps:
	MOVW	LR, R0

pagefault:

/*
 * map data virtually and make space to save
 */
	MOVW	R0, SPR(SAVEXX)	/* vector */
	MOVW	R1, SPR(SAVER1)
	SYNC
	ISYNC
	MOVW	MSR, R0
	OR	$(MSR_DR|MSR_ME), R0		/* make data space usable */
	SYNC
	MOVW	R0, MSR
	MSRSYNC
	SUB	$UREGSPACE, R1

	MOVW	SPR(SRR0), R0	/* save SRR0/SRR1 now, since DLTB might be missing stack page */
	MOVW	R0, LR
	MOVW	SPR(SRR1), R0


@@ 614,20 604,6 @@ restoreureg:
	MOVW	SPR(SAVER0), R0
	RFI

TEXT	powerdownled(SB), $0

	MOVW	$0x10002200,R11
	MOVW	$0,R7
	MOVW	R7,0(R11)
	RETURN

TEXT	powerupled(SB), $0

	MOVW	$0x10002200,R11
	MOVW	$2,R7
	MOVW	R7,0(R11)
	RETURN

GLOBL	mach0+0(SB), $MACHSIZE
GLOBL	spltbl+0(SB), $4
GLOBL	intrtbl+0(SB), $4

M mpc/main.c => mpc/main.c +12 -8
@@ 30,21 30,24 @@ flash(void)
void
main(void)
{
	int i;

	machinit();
	clockinit();
	confinit();
	xinit();
	trapinit();
	printinit();
	cpminit();
	uartinstall();
	print("hello world\n");

	delay(100);
delay(500);
	spllo();
	for(i=0; ; i++) {
		print("hello again %d\n", i);
		delay(100);
	}

	reset();

	*(uchar*)0 = 0;
	for(;;)
		;
}

void


@@ 133,7 136,8 @@ iprint(char *fmt, ...)
	n = doprint(buf, buf+sizeof(buf), fmt, arg) - buf;
	va_end(arg);

	print("%s", buf);
//	putstrn(buf, n);
//	uartwait();

	return n;
}

M mpc/mem.h => mpc/mem.h +23 -1
@@ 50,8 50,30 @@
#define MSR_LE		(1<<0)		/* Little-Endian enable */

/*
 * Traps
 * Exception codes (trap vectors)
 */
#define	CRESET	0x01
#define	CMCHECK 0x02
#define	CDSI	0x03
#define	CISI	0x04
#define	CEI	0x05
#define	CALIGN	0x06
#define	CPROG	0x07
#define	CFPU	0x08
#define	CDEC	0x09
#define	CSYSCALL 0x0C
#define	CTRACE	0x0D
#define	CFPA	0x0E
/* rest are power-implementation dependent */
#define	CEMU	0x10
#define	CIMISS	0x11
#define	CDMISS	0x12
#define	CITLBE	0x13
#define	CDTLBE	0x14
#define	CDBREAK	0x1C
#define	CIBREAK	0x1D
#define	CPBREAK	0x1E
#define	CDPORT	0x1F

/*
 * Magic registers

M mpc/trap.c => mpc/trap.c +471 -51
@@ 3,73 3,439 @@
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"io.h"
#include	"ureg.h"
#include	"io.h"
#include	"../port/error.h"

/* Give enough context in the ureg to produce a kernel stack for
 * a sleeping process
 */
enum 
{
	Maxhandler=	32+16,		/* max number of interrupt handlers */
};

typedef struct Handler	Handler;
struct Handler
{
	void	(*r)(Ureg*, void*);
	void	*arg;
	Handler	*next;
	int	edge;
	int	nintr;
	ulong	ticks;
	int	maxtick;
};

struct
{
	Handler	*ivec[128];
	Handler	h[Maxhandler];
	int	free;
} halloc;

void	kernfault(Ureg*, int);

char *excname[] =
{
	"reserved 0",
	"system reset",
	"machine check",
	"data access",
	"instruction access",
	"external interrupt",
	"alignment",
	"program exception",
	"floating-point unavailable",
	"decrementer",
	"i/o controller interface error",
	"reserved B",
	"system call",
	"trace trap",
	"floating point assist",
	"reserved F",
	"software emulation",
	"ITLB miss",
	"DTLB miss",
	"ITLB error",
	"DTLB error",
	"reserved 15",
	"reserved 16",
	"reserved 17",
	"reserved 18",
	"reserved 19",
	"reserved 1A",
	"reserved 1B",
	"data breakpoint",
	"instruction breakpoint",
	"peripheral breakpoint",
	"development port",
	/* the following are made up on a program exception */
	"floating point exception",		/* 20: FPEXC */
	"illegal instruction",	/* 21 */
	"privileged instruction",	/* 22 */
	"trap",	/* 23 */
	"illegal operation",	/* 24 */
	"breakpoint",	/* 25 */
};

char *fpcause[] =
{
	"inexact operation",
	"division by zero",
	"underflow",
	"overflow",
	"invalid operation",
};
char	*fpexcname(Ureg*, ulong, char*);
#define FPEXPMASK	0xfff80300		/* Floating exception bits in fpscr */


char *regname[]={
	"CAUSE",	"SRR1",
	"PC",		"GOK",
	"LR",		"CR",
	"XER",	"CTR",
	"R0",		"R1",
	"R2",		"R3",
	"R4",		"R5",
	"R6",		"R7",
	"R8",		"R9",
	"R10",	"R11",
	"R12",	"R13",
	"R14",	"R15",
	"R16",	"R17",
	"R18",	"R19",
	"R20",	"R21",
	"R22",	"R23",
	"R24",	"R25",
	"R26",	"R27",
	"R28",	"R29",
	"R30",	"R31",
};

void
setkernur(Ureg* ureg, Proc* p)
sethvec(int v, void (*r)(void))
{
	ureg->pc = p->sched.pc;
	ureg->sp = p->sched.sp+4;
	ulong *vp, pa, o;

	vp = (ulong*)(0xfff00000+v);
	vp[0] = 0x7c1043a6;	/* MOVW R0, SPR(SPRG0) */
	vp[1] = 0x7c0802a6;	/* MOVW LR, R0 */
	vp[2] = 0x7c1243a6;	/* MOVW R0, SPR(SPRG2) */
	pa = PADDR(r);
	o = pa >> 25;
	if(o != 0 && o != 0x7F){
		/* a branch too far */
		vp[3] = (15<<26)|(pa>>16);	/* MOVW $r&~0xFFFF, R0 */
		vp[4] = (24<<26)|(pa&0xFFFF);	/* OR $r&0xFFFF, R0 */
		vp[5] = 0x7c0803a6;	/* MOVW	R0, LR */
		vp[6] = 0x4e800021;	/* BL (LR) */
	}else
		vp[3] = (18<<26)|(pa&0x3FFFFFC)|3;	/* bla */
	dcflush(vp, 8*sizeof(ulong));
}

/* This routine must save the values of registers the user is not permitted to write
 * from devproc and then restore the saved values before returning
 */
void
setregisters(Ureg* ureg, char* pureg, char* uva, int n)
sethvec2(int v, void (*r)(void))
{
	USED(ureg, pureg, uva, n);
	panic("not done");
	ulong *vp;

	vp = (ulong*)KADDR(v);
	vp[0] = (18<<26)|(PADDR(r))|2;	/* ba */
	dcflush(vp, sizeof(*vp));
}

void
dumpregs(Ureg* ureg)
trap(Ureg *ur)
{
	USED(ureg);
	panic("not done");
	int ecode;
	static struct {int callsched;} c = {1};

	ecode = (ur->cause >> 8) & 0xff;
	if(ecode < 0 || ecode >= 0x1F)
		ecode = 0x1F;
	switch(ecode){
	case CEI:
		intr(ur);
		break;

	case CDEC:
		clockintr(ur);
		break;

	case CMCHECK:
	case CDSI:
	case CISI:
	case CIMISS:
	case CDMISS:
	case CITLBE:
	case CDTLBE:
		goto Default;
		break;

	case CEMU:
		print("pc=#%lux op=#%8.8lux\n", ur->pc, *(ulong*)ur->pc);
		goto Default;
		break;

	case CPROG:
		if(ur->status & (1<<19))
			ecode = 0x20;
		if(ur->status & (1<<18))
			ecode = 0x21;
		if(ur->status & (1<<17))
			ecode = 0x22;
		goto Default;

	Default:
	default:
		print("kernel %s pc=0x%lux\n", excname[ecode], ur->pc);
		dumpregs(ur);
		dumpstack();
		if(m->machno == 0)
			spllo();
		exit(1);
	}

	splhi();
}

void
dumpstack(void)
spurious(Ureg *ur, void *a)
{
	panic("not done");
	USED(a);
	print("SPURIOUS interrupt pc=0x%lux cause=0x%lux\n",
		ur->pc, ur->cause);
	panic("bad interrupt");
}

ulong
userpc(void)
#define	LEV(n)	(((n)<<1)|1)
#define	IRQ(n)	(((n)<<1)|0)

Lock	veclock;

void
trapinit(void)
{
	Ureg *ureg;
	int i;
	IMM *io;

	ureg = (Ureg*)up->dbgreg;
	return ureg->pc;

	io = m->iomem;
	io->sypcr &= ~(1<<3);	/* disable watchdog (821/823) */
	io->simask = 0;	/* mask all */
	io->siel = ~0;	/* edge sensitive, wake on all */
	io->cicr = 0;	/* disable CPM interrupts */
	io->cipr = ~0;	/* clear all interrupts */
	io->cimr = 0;	/* mask all events */
	io->cicr = (0xE1<<16)|(CPIClevel<<13)|(0x1F<<8);
	io->cicr |= 1 << 7;	/* enable */
	io->tbscr = 1;	/* TBE */
	io->simask |= 1<<(31-LEV(CPIClevel));	/* CPM's level */
	eieio();
	putdec(~0);

	/*
	 * set all exceptions to trap
	 */
	for(i = 0x0; i < 0x3000; i += 0x100)
		sethvec(i, trapvec);

	//sethvec(CEI<<8, intrvec);
	//sethvec2(CIMISS<<8, itlbmiss);
	//sethvec2(CDMISS<<8, dtlbmiss);
}

ulong
dbgpc(Proc *p)
void
intrenable(int v, void (*r)(Ureg*, void*), void *arg, int)
{
	Ureg *ureg;
	Handler *h;
	IMM *io;

	ureg = p->dbgreg;
	if(ureg == 0)
		return 0;
	if(halloc.free >= Maxhandler)
		panic("out of interrupt handlers");
	v -= VectorPIC;
	if(v < 0 || v >= nelem(halloc.ivec))
		panic("intrenable(%d)", v+VectorPIC);
	ilock(&veclock);
	if(v < VectorCPIC || (h = halloc.ivec[v]) == nil){
		h = &halloc.h[halloc.free++];
		h->next = halloc.ivec[v];
		halloc.ivec[v] = h;
	}
	h->r = r;
	h->arg = arg;

	return ureg->pc;
	/*
	 * enable corresponding interrupt in SIU/CPM
	 */

	eieio();
	io = m->iomem;
	if(v >= VectorCPIC){
		v -= VectorCPIC;
		io->cimr |= 1<<(v&0x1F);
	}
	else if(v >= VectorIRQ)
		io->simask |= 1<<(31-IRQ(v&7));
	else
		io->simask |= 1<<(31-LEV(v));
	eieio();
	iunlock(&veclock);
}

/*
 * called directly by l.s:/intrvec
 */
void
intr(Ureg *ur)
{
	int b, v;
	IMM *io;
	Handler *h;
	long t0;

	ur->cause &= ~0xff;
	io = m->iomem;
	b = io->sivec>>2;
	v = b>>1;
	if(b & 1) {
		if(v == CPIClevel){
			io->civr = 1;
			eieio();
			v = VectorCPIC+(io->civr>>11);
		}
	}else
		v += VectorIRQ;
	ur->cause |= v;
	h = halloc.ivec[v];
	if(h == nil){
		print("unknown interrupt %d pc=0x%lux\n", v, ur->pc);
		uartwait();
		return;
	}
	if(h->edge){
		io->sipend |= 1<<(31-b);
		eieio();
	}
	/*
	 *  call the interrupt handlers
	 */
	do {
		h->nintr++;
		t0 = getdec();
		(*h->r)(ur, h->arg);
		t0 -= getdec();
		h->ticks += t0;
		if(h->maxtick < t0)
			h->maxtick = t0;
		h = h->next;
	} while(h != nil);
	if(v >= VectorCPIC)
		io->cisr |= 1<<(v-VectorCPIC);
	eieio();
}

int
intrstats(char *buf, int bsize)
{
	Handler *h;
	int i, n;

	n = 0;
	for(i=0; i<nelem(halloc.ivec) && n < bsize; i++)
		if((h = halloc.ivec[i]) != nil && h->nintr)
			n += snprint(buf+n, bsize-n, "%3d %lud %lud %lud\n", i, h->nintr, h->ticks, h->maxtick);
	return n;
}

char*
fpexcname(Ureg *ur, ulong fpscr, char *buf)
{
	int i;
	char *s;
	ulong fppc;

	fppc = ur->pc;
	s = 0;
	fpscr >>= 3;		/* trap enable bits */
	fpscr &= (fpscr>>22);	/* anded with exceptions */
	for(i=0; i<5; i++)
		if(fpscr & (1<<i))
			s = fpcause[i];
	if(s == 0)
		return "no floating point exception";
	sprint(buf, "%s fppc=0x%lux", s, fppc);
	return buf;
}

#define KERNPC(x)	(KTZERO<(ulong)(x)&&(ulong)(x)<(ulong)etext)

void
kernfault(Ureg *ur, int code)
{
	Label l;

	print("panic: kfault %s dar=0x%lux\n", excname[code], getdar());
	print("u=0x%lux status=0x%lux pc=0x%lux sp=0x%lux\n",
				up, ur->status, ur->pc, ur->sp);
	dumpregs(ur);
	l.sp = ur->sp;
	l.pc = ur->pc;
	dumpstack();
	for(;;)
		sched();
}

void
dumpstack(void)
{
	ulong l, v;
	int i;

	if(up == 0)
		return;
	i = 0;
	for(l=(ulong)&l; l<(ulong)(up->kstack+KSTACK); l+=4){
		v = *(ulong*)l;
		if(KTZERO < v && v < (ulong)etext){
			print("%lux=%lux, ", l, v);
			if(i++ == 4){
				print("\n");
				i = 0;
			}
		}
	}
}

void
dumpregs(Ureg *ur)
{
	int i;
	ulong *l;
	if(up) {
		print("registers for %s %d\n", up->text, up->pid);
		if(ur->usp < (ulong)up->kstack ||
		   ur->usp > (ulong)up->kstack+KSTACK)
			print("invalid stack ptr\n");
	}
	else
		print("registers for kernel\n");

	print("dsisr\t%.8lux\tdar\t%.8lux\n", getdsisr(), getdar());
	l = &ur->cause;
	for(i=0; i<sizeof regname/sizeof(char*); i+=2, l+=2)
		print("%s\t%.8lux\t%s\t%.8lux\n", regname[i], l[0], regname[i+1], l[1]);
}

static void
linkproc(void)
{
	spllo();
	up->kpfun(up->kparg);
	(*up->kpfun)(up->kparg);
	pexit("", 0);
}

void
kprocchild(Proc* p, void (*func)(void*), void* arg)
kprocchild(Proc *p, void (*func)(void*), void *arg)
{
	p->sched.pc = (ulong)linkproc;
	p->sched.sp = (ulong)p->kstack+KSTACK;


@@ 78,10 444,28 @@ kprocchild(Proc* p, void (*func)(void*), void* arg)
	p->kparg = arg;
}

int
isvalid_pc(ulong pc)
{
	return KERNPC(pc) && (pc&3) == 0;
}

void
dumplongs(char*, ulong*, int)
{
}

void
forkchild(Proc *p, Ureg *ureg)
reset(void)
{
	USED(p, ureg);
	IMM *io;

	io = m->iomem;
	io->plprcrk = KEEP_ALIVE_KEY;	// unlock
	io->plprcr |= IBIT(24);		// enable checkstop reset
	putmsr(getmsr() & ~MSR_ME);
	// cause checkstop -> causes reset
	*(ulong*)(0) = 0;
}

/*


@@ 112,35 496,71 @@ execregs(ulong entry, ulong ssize, ulong nargs)
}

void
trap(Ureg *ur)
forkchild(Proc *p, Ureg *ur)
{
	USED(ur);
	Ureg *cur;

	p->sched.sp = (ulong)p->kstack+KSTACK-UREGSIZE;
	p->sched.pc = (ulong)forkret;

	cur = (Ureg*)(p->sched.sp+2*BY2WD);
	memmove(cur, ur, sizeof(Ureg));

	cur->pc += 4;

	/* Things from bottom of syscall we never got to execute */
	p->psstate = 0;
	p->insyscall = 0;
}

/*
 * called directly by l.s:/intrvec
ulong
userpc(void)
{
	Ureg *ureg;

	ureg = (Ureg*)up->dbgreg;
	return ureg->pc;
}


// need to be in l.s
void
forkret(void)
{
	panic("forkret");
}
/* This routine must save the values of registers the user is not 
 * permitted to write from devproc and then restore the saved values 
 * before returning
 */
void
intr(Ureg *ur)
setregisters(Ureg *xp, char *pureg, char *uva, int n)
{
	USED(ur);
	ulong status;

	status = xp->status;
	memmove(pureg, uva, n);
	xp->status = status;
}

/* Give enough context in the ureg to produce a kernel stack for
 * a sleeping process
 */
void
intrenable(int v, void (*r)(Ureg*, void*), void *arg, int)
setkernur(Ureg* ureg, Proc* p)
{
	USED(v, r, arg);
	ureg->pc = p->sched.pc;
	ureg->sp = p->sched.sp+4;
}

void
reset(void)
ulong
dbgpc(Proc *p)
{
	IMM *io;
	Ureg *ureg;

	io = m->iomem;
	io->plprcrk = KEEP_ALIVE_KEY;	// unlock
	io->plprcr |= IBIT(24);		// enable checkstop reset
	putmsr(getmsr() & ~MSR_ME);
	// cause checkstop -> causes reset
	*(ulong*)(0) = 0;
	ureg = p->dbgreg;
	if(ureg == 0)
		return 0;

	return ureg->pc;
}