~kris/9p

9hist

725df887ee04f36f44a028091facf2cc698135fa — David du Colombier 24 years ago 33da0b5
Plan 9 from Bell Labs 2001-12-07
M ip/devip.c => ip/devip.c +1 -0
@@ 496,6 496,7 @@ ipopen(Chan* c, int omode)
	c->mode = openmode(omode);
	c->flag |= COPEN;
	c->offset = 0;
	c->iounit = qiomaxatomic;
	return c;
}


A mtx/clock.c => mtx/clock.c +56 -0
@@ 0,0 1,56 @@
#include	"u.h"
#include	"../port/lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"io.h"
#include	"ureg.h"

void
clockintr(Ureg *ureg)
{
	// this needs to be here for synchronizing mp clocks
	// see pc/mp.c's squidboy()
	fastticks(nil);

	if(m->flushmmu){
		if(up)
			flushmmu();
		m->flushmmu = 0;
	}

	portclock(ureg);
}

void
delay(int l)
{
	ulong i, j;

//	j = m->delayloop;
//	while(l-- > 0)
//		for(i=0; i < j; i++)
//			;
}

void
microdelay(int l)
{
	ulong i;

//	l *= m->delayloop;
//	l += 500;
//	l /= 1000;
//	if(l <= 0)
//		l = 1;
//	for(i = 0; i < l; i++)
//		;
}

vlong
fastticks(uvlong *hz)
{
	if(hz)
		*hz = HZ;
	return m->ticks;
}

M mtx/l.s => mtx/l.s +245 -9
@@ 1,14 1,22 @@
#include	"mem.h"

/* use of SPRG registers in save/restore */
#define	SAVER0	SPRG0
#define	SAVER1	SPRG1
#define	SAVELR	SPRG2
#define	SAVEXX	SPRG3

/* special instruction definitions */
#define	BDNZ	BC	16,0,
#define	BDNE	BC	0,2,
#define	NOOP	OR	R0,R0,R0
#define	TLBIA	WORD	$(31<<26)
//#define	TLBIA	WORD	$(31<<26)
#define	TLBIA	WORD	$((31<<26)|(370<<1))
//#define	MFTB(tbr,d)	WORD	$((31<<26)|((d)<<21)|((tbr&0x1f)<<16)|(((tbr>>5)&0x1f)<<11)|(371<<1))

/* on some models mtmsr doesn't synchronise enough (eg, 603e) */
#define	MSRSYNC	SYNC; ISYNC

/* Be-ware 603e chip bugs (mtmsr instruction) */
#define	FIX603e	CROR	0,0,0
#undef FIX603e
#define	FIX603e	ISYNC; SYNC
#define	UREGSPACE	(UREGSIZE+8)

	TEXT start(SB), $-4
	MOVW	$setSB(SB), R2


@@ 23,7 31,7 @@ TEXT	splhi(SB), $0
	RLWNM	$0, R3, $~MSR_EE, R4
	SYNC
	MOVW	R4, MSR
	FIX603e
	MSRSYNC
	RETURN

TEXT	splx(SB), $0


@@ 36,7 44,7 @@ TEXT	splxpc(SB), $0
	RLWMI	$0, R3, $MSR_EE, R4
	SYNC
	MOVW	R4, MSR
	FIX603e
	MSRSYNC
	RETURN

TEXT	spllo(SB), $0


@@ 44,7 52,7 @@ TEXT	spllo(SB), $0
	OR	$MSR_EE, R3, R4
	SYNC
	MOVW	R4, MSR
	FIX603e
	MSRSYNC
	RETURN

TEXT	spldone(SB), $0


@@ 68,3 76,231 @@ TEXT	gotolabel(SB), $-4
	MOVW	0(R3), R1
	MOVW	$1, R3
	RETURN

TEXT	touser(SB), $-4
	MOVW	$(UTZERO+32), R5	/* header appears in text */
	MOVW	$(MSR_EE|MSR_PR|MSR_ME|MSR_IR|MSR_DR|MSR_RI), R4
	MOVW	R4, SPR(SRR1)
	MOVW	R3, R1
	MOVW	R5, SPR(SRR0)
	RFI

TEXT	icflush(SB), $-4	/* icflush(virtaddr, count) */
	MOVW	n+4(FP), R4
	RLWNM	$0, R3, $~(CACHELINESZ-1), R5
	SUB	R5, R3
	ADD	R3, R4
	ADD		$(CACHELINESZ-1), R4
	SRAW	$CACHELINELOG, R4
	MOVW	R4, CTR
icf0:	ICBI	(R5)
	ADD	$CACHELINESZ, R5
	BDNZ	icf0
	ISYNC
	RETURN

TEXT	dcflush(SB), $-4	/* dcflush(virtaddr, count) */
	MOVW	n+4(FP), R4
	RLWNM	$0, R3, $~(CACHELINESZ-1), R5
	CMP	R4, $0
	BLE	dcf1
	SUB	R5, R3
	ADD	R3, R4
	ADD		$(CACHELINESZ-1), R4
	SRAW	$CACHELINELOG, R4
	MOVW	R4, CTR
dcf0:	DCBF	(R5)
	ADD	$CACHELINESZ, R5
	BDNZ	dcf0
dcf1:
	RETURN

TEXT	tas(SB), $0
	SYNC
	MOVW	R3, R4
	MOVW	$0xdead,R5
tas1:
	DCBF	(R4)	/* fix for 603x bug */
	LWAR	(R4), R3
	CMP	R3, $0
	BNE	tas0
	STWCCC	R5, (R4)
	BNE	tas1
tas0:
	SYNC
	ISYNC
	RETURN

TEXT	getpvr(SB), $0
	MOVW	SPR(PVR), R3
	RETURN

TEXT	getdec(SB), $0
	MOVW	SPR(DEC), R3
	RETURN

TEXT	putdec(SB), $0
	MOVW	R3, SPR(DEC)
	RETURN

TEXT	getdar(SB), $0
	MOVW	SPR(DAR), R3
	RETURN

TEXT	getdsisr(SB), $0
	MOVW	SPR(DSISR), R3
	RETURN

TEXT	getmsr(SB), $0
	MOVW	MSR, R3
	RETURN

TEXT	putmsr(SB), $0
	SYNC
	MOVW	R3, MSR
	MSRSYNC
	RETURN

TEXT	eieio(SB), $0
	EIEIO
	RETURN

TEXT	tlbflushall(SB), $0
	TLBIA
	RETURN

TEXT	tlbflush(SB), $0
	TLBIE	R3
	RETURN

TEXT	gotopc(SB), $0
	MOVW	R3, CTR
	MOVW	LR, R31	/* for trace back */
	BR	(CTR)

/*
 * traps force memory mapping off.
 * the following code has been executed at the exception
 * vector location
 *	MOVW R0, SPR(SAVER0)
 *	MOVW LR, R0
 *	MOVW R0, SPR(SAVELR) 
 *	bl	trapvec(SB)
 */
TEXT	trapvec(SB), $-4
	MOVW	LR, R0
	MOVW	R1, SPR(SAVER1)
	MOVW	R0, SPR(SAVEXX)	/* vector */

/*
	to enable hardware break points
	MOVW	MSR, R1
	OR		$(MSR_RI), R1
	MOVW	R1, MSR
	ISYNC
*/	

	/* did we come from user space */
	MOVW	SPR(SRR1), R0
	MOVW	CR, R1
	MOVW	R0, CR
	BC	4,17,ktrap
	
	/* switch to kernel stack */
	MOVW	R1, CR
	MOVW	$(MACHADDR&~KZERO), R1	/* PADDR(m->) */
	MOVW	12(R1), R1				/* m->proc  */
	RLWNM	$0, R1, $~KZERO, R1		/* PADDR(m->proc) */
	MOVW	8(R1), R1				/* m->proc->kstack */
	RLWNM	$0, R1, $~KZERO, R1		/* PADDR(m->proc->kstack) */
	ADD	$(KSTACK-UREGSIZE), R1
	BL	saveureg(SB)
	BL	trap(SB)
	BR	restoreureg
ktrap:
	MOVW	R1, CR
	MOVW	SPR(SAVER1), R1
	RLWNM	$0, R1, $~KZERO, R1		/* PADDR(m->proc->kstack) */
	SUB	$UREGSPACE, R1
	BL	saveureg(SB)
	BL	trap(SB)
	BR	restoreureg


/*
 * enter with stack set and mapped.
 * on return, SB (R2) has been set, and R3 has the Ureg*,
 * the MMU has been re-enabled, kernel text and PC are in KSEG,
 * R(MACH) has been set, and R0 contains 0.
 *
 */
TEXT	saveureg(SB), $-4
/*
 * save state
 */
	MOVMW	R2, 48(R1)	/* r2:r31 */
	MOVW	$setSB(SB), R2
	MOVW	$(MACHADDR&~KZERO), R(MACH)
	MOVW	12(R(MACH)), R(USER)
	MOVW	$MACHADDR, R(MACH)
	MOVW	SPR(SAVER1), R4
	MOVW	R4, 44(R1)
	MOVW	SPR(SAVER0), R5
	MOVW	R5, 40(R1)
	MOVW	CTR, R6
	MOVW	R6, 36(R1)
	MOVW	XER, R4
	MOVW	R4, 32(R1)
	MOVW	CR, R5
	MOVW	R5, 28(R1)
	MOVW	SPR(SAVELR), R6	/* LR */
	MOVW	R6, 24(R1)
	/* pad at 20(R1) */
	MOVW	SPR(SRR0), R0
	MOVW	R0, 16(R1)				/* old PC */
	MOVW	SPR(SRR1), R0
	MOVW	R0, 12(R1)				/* old status */
	MOVW	SPR(SAVEXX), R0
	MOVW	R0, 8(R1)	/* cause/vector */
	ADD	$8, R1, R3	/* Ureg* */
	OR	$KZERO, R3	/* fix ureg */
	STWCCC	R3, (R1)	/* break any pending reservations */
	MOVW	$0, R0	/* compiler/linker expect R0 to be zero */

	MOVW	MSR, R5
//	OR	$(MSR_IR|MSR_DR|MSR_RI), R5	/* enable MMU */
	MOVW	R5, SPR(SRR1)
	MOVW	LR, R31
//	OR	$KZERO, R31	/* return PC in KSEG0 */
	MOVW	R31, SPR(SRR0)
//	OR	$KZERO, R1	/* fix stack pointer */
	RFI	/* returns to trap handler */

/*
 * restore state from Ureg and return from trap/interrupt
 */
TEXT	forkret(SB), $0
	BR	restoreureg

restoreureg:
	MOVMW	48(R1), R2	/* r2:r31 */
	/* defer R1 */
	MOVW	40(R1), R0
	MOVW	R0, SPR(SAVER0)
	MOVW	36(R1), R0
	MOVW	R0, CTR
	MOVW	32(R1), R0
	MOVW	R0, XER
	MOVW	28(R1), R0
	MOVW	R0, CR	/* CR */
	MOVW	24(R1), R0
	MOVW	R0, LR
	/* pad, skip */
	MOVW	16(R1), R0
	MOVW	R0, SPR(SRR0)	/* old PC */
	MOVW	12(R1), R0
	MOVW	R0, SPR(SRR1)	/* old MSR */
	/* cause, skip */
	MOVW	44(R1), R1	/* old SP */
	MOVW	SPR(SAVER0), R0
	RFI

M mtx/main.c => mtx/main.c +350 -3
@@ 13,10 13,357 @@ FPsave	initfp;
void
main(void)
{
//	xinit();
	printinit();
	conf.nmach = 1;
	machinit();
	active.machs = 1;
	active.exiting = 0;
	i8250console();
	print("\nPlan 9\n");
//	cpuidentify();
//	confinit();
//	xinit();
	trapinit();
print("trapinit done\n");
*(ulong*)-1 = 0;
print("survived!\n");
spllo();
putdec(64);
print("still here\n");
{ void (*f)(void); f = (void (*)(void))0x200; f(); }
for(;;);
//	printinit();
//	cpuidprint();
//	mmuinit();
//	procinit0();
//	initseg();
//	links();
//	chandevreset();
//	pageinit();
//	swapinit();
//	userinit();
//	schedinit();
}

void
machinit(void)
{
	memset(m, 0, sizeof(Mach));

	/*
	 * For polled uart output at boot, need
	 * a default delay constant. 100000 should
	 * be enough for a while. Cpuidentify will
	 * calculate the real value later.
	 */
//	m->loopconst = 100000;
}

static struct
{
	char	*name;
	char *val;
}
plan9ini[] =
{
	{ "console", "0" },
};

char*
getconf(char *name)
{
	int i;

	for(i = 0; i < nelem(plan9ini); i++)
		if(cistrcmp(name, plan9ini[i].name) == 0)
			return plan9ini[i].val;
	return nil;
}

void
init0(void)
{
//	char **p, *q, name[KNAMELEN];
//	int n;

print("init0\n");

	up->nerrlab = 0;

	spllo();

	/*
	 * These are o.k. because rootinit is null.
	 * Then early kproc's will have a root and dot.
	 */
	up->slash = namec("#/", Atodir, 0, 0);
	cnameclose(up->slash->name);
	up->slash->name = newcname("/");
	up->dot = cclone(up->slash);

	chandevinit();

	if(!waserror()){
		ksetenv("cputype", "power");
		if(cpuserver)
			ksetenv("service", "cpu");
		else
			ksetenv("service", "terminal");
		
/*
		for(p = confenv; *p; p++) {
			q = strchr(p[0], '=');
			if(q == 0)
				continue;
			n = q-p[0];
			if(n >= KNAMELEN)
				n = KNAMELEN-1;
			memmove(name, p[0], n);
			name[n] = 0;
			ksetenv(name, q+1);
		}
*/
		poperror();
	}
	kproc("alarm", alarmkproc, 0);
	touser((void*)(USTKTOP-8));
}

void
userinit(void)
{
	Proc *p;
	Segment *s;
	KMap *k;
	Page *pg;

	p = newproc();
	p->pgrp = newpgrp();
	p->egrp = smalloc(sizeof(Egrp));
	p->egrp->ref = 1;
	p->fgrp = dupfgrp(nil);
	p->rgrp = newrgrp();
	p->procmode = 0640;

	strcpy(p->text, "*init*");
	strcpy(p->user, eve);
	p->fpstate = FPinit;

	/*
	 * Kernel Stack
	 *
	 * N.B. The -12 for the stack pointer is important.
	 *	4 bytes for gotolabel's return PC
	 */
	p->sched.pc = (ulong)init0;
	p->sched.sp = (ulong)p->kstack+KSTACK-(1+MAXSYSARG)*BY2WD;

	/*
	 * User Stack
	 */
	s = newseg(SG_STACK, USTKTOP-USTKSIZE, USTKSIZE/BY2PG);
	p->seg[SSEG] = s;
	pg = newpage(1, 0, USTKTOP-BY2PG);
	segpage(s, pg);

	/*
	 * Text
	 */
	s = newseg(SG_TEXT, UTZERO, 1);
	s->flushme++;
	p->seg[TSEG] = s;
	pg = newpage(1, 0, UTZERO);
	memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl));
	segpage(s, pg);
	k = kmap(s->map[0]->pages[0]);
	memmove((ulong*)VA(k), initcode, sizeof initcode);
	kunmap(k);

	ready(p);
}

void
exit(int ispanic)
{
	int ms, once;

	lock(&active);
	if(ispanic)
		active.ispanic = ispanic;
	else if(m->machno == 0 && (active.machs & (1<<m->machno)) == 0)
		active.ispanic = 0;
	once = active.machs & (1<<m->machno);
	active.machs &= ~(1<<m->machno);
	active.exiting = 1;
	unlock(&active);

	if(once)
		print("cpu%d: exiting\n", m->machno);
	spllo();
	for(ms = 5*1000; ms > 0; ms -= TK2MS(2)){
		delay(TK2MS(2));
		if(active.machs == 0 && consactive() == 0)
			break;
	}

	if(active.ispanic && m->machno == 0){
		if(cpuserver)
			delay(10000);
		else
			for(;;);
	}
	else
		delay(1000);

	for(;;)
		;
}

/*
 *  set up floating point for a new process
 */
void
procsetup(Proc *p)
{
	USED(p);
}

/*
 *  Save the mach dependent part of the process state.
 */
void
procsave(Proc *p)
{
	USED(p);
}

void
confinit(void)
{
	int nbytes;
	ulong pa;

	conf.nmach = 1;		/* processors */
	conf.nproc = 60;	/* processes */

	// hard wire for now
	pa = 0x200000;		// leave 2 Meg for kernel
	nbytes = 8*1024*1024;	// leave room at the top as well
	
	conf.npage0 = nbytes/BY2PG;
	conf.base0 = pa;
	
	conf.npage1 = 0;
	conf.base1 = pa;

	conf.npage = conf.npage0 + conf.npage1;

	conf.upages = (conf.npage*60)/100;
	conf.ialloc = ((conf.npage-conf.upages)/2)*BY2PG;

	/* set up other configuration parameters */
	conf.nswap = 0;
	conf.nswppo = 0; 
	conf.nimage = 20;

	conf.copymode = 0;		/* copy on write */
}

static int
getcfields(char* lp, char** fields, int n, char* sep)
{
	int i;

	for(i = 0; lp && *lp && i < n; i++){
		while(*lp && strchr(sep, *lp) != 0)
			*lp++ = 0;
		if(*lp == 0)
			break;
		fields[i] = lp;
		while(*lp && strchr(sep, *lp) == 0){
			if(*lp == '\\' && *(lp+1) == '\n')
				*lp++ = ' ';
			lp++;
		}
	}

	return i;
}

int
isaconfig(char *class, int ctlrno, ISAConf *isa)
{
	int i;
	char cc[KNAMELEN], *p;

	sprint(cc, "%s%d", class, ctlrno);

	p = getconf(cc);
	if(p == 0)
		return 0;
	isa->nopt = tokenize(p, isa->opt, NISAOPT);
	for(i = 0; i < isa->nopt; i++){
		p = isa->opt[i];
		if(cistrncmp(p, "type=", 5) == 0)
			isa->type = p + 5;
		else if(cistrncmp(p, "port=", 5) == 0)
			isa->port = strtoul(p+5, &p, 0);
		else if(cistrncmp(p, "irq=", 4) == 0)
			isa->irq = strtoul(p+4, &p, 0);
		else if(cistrncmp(p, "dma=", 4) == 0)
			isa->dma = strtoul(p+4, &p, 0);
		else if(cistrncmp(p, "mem=", 4) == 0)
			isa->mem = strtoul(p+4, &p, 0);
		else if(cistrncmp(p, "size=", 5) == 0)
			isa->size = strtoul(p+5, &p, 0);
		else if(cistrncmp(p, "freq=", 5) == 0)
			isa->freq = strtoul(p+5, &p, 0);
	}
	return 1;
}

int
cistrcmp(char *a, char *b)
{
	int ac, bc;

	for(;;){
		ac = *a++;
		bc = *b++;
	
		if(ac >= 'A' && ac <= 'Z')
			ac = 'a' + (ac - 'A');
		if(bc >= 'A' && bc <= 'Z')
			bc = 'a' + (bc - 'A');
		ac -= bc;
		if(ac)
			return ac;
		if(bc == 0)
			break;
	}
	return 0;
}

int
cistrncmp(char *a, char *b, int n)
{
	unsigned ac, bc;

	while(n > 0){
		ac = *a++;
		bc = *b++;
		n--;

		if(ac >= 'A' && ac <= 'Z')
			ac = 'a' + (ac - 'A');
		if(bc >= 'A' && bc <= 'Z')
			bc = 'a' + (bc - 'A');

		ac -= bc;
		if(ac)
			return ac;
		if(bc == 0)
			break;
	}

	for(;;);
	return 0;
}

M mtx/mem.h => mtx/mem.h +3 -1
@@ 81,7 81,7 @@
#define SIA		955		/* Sampled Instruction Address */
#define SDA		959		/* Sampled Data Address */

#define BIT(i)	(1<<(32-(i)))	/* Silly backwards register bit numbering scheme */
#define BIT(i)	(1<<(31-(i)))	/* Silly backwards register bit numbering scheme */

/*
 * Bit encodings for Machine State Register (MSR)


@@ 222,3 222,5 @@
#define	FLASHAorB	0xfff00000

#define isphys(x) (((ulong)x&KZERO)!=0)

#define getpgcolor(a)	0

M mtx/mmu.c => mtx/mmu.c +1 -116
@@ 13,8 13,6 @@ mmuinit(void)
	int i;

	print("mmuinit\n");
	for(i=0; i<STLBSIZE; i++)
		m->stb[i].virt = TLBINVLAID;
}

void


@@ 43,7 41,7 @@ if(0)print("mmuswitch()\n");
		p->newtlb = 0;
	}
	tp = p->pidonmach[m->machno];
	putcasid(tp);
//	putcasid(tp);
}

void


@@ 54,119 52,6 @@ if(0)print("mmurelease(%ld)\n", p->pid);
}

void
purgetlb(int pid)
{
	int i, mno;
	Proc *sp, **pidproc;
	Softtlb *entry, *etab;

if(0)print("purgetlb: pid = %d\n", pid);
	m->tlbpurge++;
	/*
	 * find all pid entries that are no longer used by processes
	 */
	mno = m->machno;
	pidproc = m->pidproc;
	for(i=1; i<NTLBPID; i++) {
		sp = pidproc[i];
		if(sp && sp->pidonmach[mno] != i)
			pidproc[i] = 0;
	}

	/*
	 * shoot down the one we want
	 */
	sp = pidproc[pid];
	if(sp != 0)
		sp->pidonmach[mno] = 0;
	pidproc[pid] = 0;

	/*
	 * clean out all dead pids from the stlb;
	 */
	entry = m->stb;
	for(etab = &entry[STLBSIZE]; entry < etab; entry++)
		if(pidproc[TLBPID(entry->virt)] == 0)
			entry->virt = TLBINVLAID;

	/*
	 * clean up the hardware
	 */
	tlbflushall();
}

int
newtlbpid(Proc *p)
{
	int i, s;
	Proc **h;

	i = m->lastpid;
	h = m->pidproc;
	for(s = 0; s < NTLBPID; s++) {
		i++;
		if(i >= NTLBPID)
			i = 1;
		if(h[i] == 0)
			break;
	}

	if(h[i]) {
		i = m->purgepid+1;
		if(i >= NTLBPID)
			i = 1;
		 m->purgepid = i;
		purgetlb(i);
	}

	if(h[i] != 0)
		panic("newtlb");

	m->pidproc[i] = p;
	p->pidonmach[m->machno] = i;
	m->lastpid = i;
if(0)print("newtlbpid: pid=%ld = tlbpid = %d\n", p->pid, i);
	return i;
}

void
putmmu(ulong va, ulong pa, Page *pg)
{
	char *ctl;
	int tp;
	ulong h;

	qlock(&m->stlblk);

	tp = up->pidonmach[m->machno];
	if(tp == 0) {
		tp = newtlbpid(up);
		putcasid(tp);
	}

	h = ((va>>12)^(va>>24)^(tp<<8)) & 0xfff;
	m->stb[h].virt = va|tp;
	m->stb[h].phys = pa;
	tlbflush(va);

	qunlock(&m->stlblk);

	ctl = &pg->cachectl[m->machno];
if(0)print("putmmu tp=%d h=%ld va=%lux pa=%lux ctl=%x\n", tp, h,va, pa, *ctl);
	switch(*ctl) {
	default:
		panic("putmmu: %d\n", *ctl);
		break;
	case PG_NOFLUSH:
		break;
	case PG_TXTFLUSH:
		dcflush((void*)pg->va, BY2PG);
		icflush((void*)pg->va, BY2PG);
		*ctl = PG_NOFLUSH;
		break;
	case PG_NEWCOL:
print("PG_NEWCOL!!\n");
		*ctl = PG_NOFLUSH;
		break;
	}
}

M mtx/trap.c => mtx/trap.c +47 -55
@@ 116,38 116,6 @@ char *regname[]={
};

void
sethvec(int v, void (*r)(void))
{
	ulong *vp, pa, o;

	vp = KADDR(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));
}

void
sethvec2(int v, void (*r)(void))
{
	ulong *vp;

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

void
trap(Ureg *ur)
{
	int ecode;


@@ 155,6 123,7 @@ trap(Ureg *ur)
	int user;
	char buf[ERRMAX];

print("trap\n");
	m->intrts = fastticks(nil);
	ecode = (ur->cause >> 8) & 0xff;
	user = (ur->srr1 & MSR_PR) != 0;


@@ 256,38 225,40 @@ spurious(Ureg *ur, void *a)
Lock	veclock;

void
sethvec(int v, void (*r)(void))
{
	ulong *vp, pa, o;

	vp = KADDR(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));
}

void
trapinit(void)
{
#ifdef	BLOG
	int i;
	IMM *io;


	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);
	putmsr(getmsr() & ~MSR_IP);

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

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

void


@@ 432,19 403,34 @@ kernfault(Ureg *ur, int code)
		sched();
}

/*
 * Fill in enough of Ureg to get a stack trace, and call a function.
 * Used by debugging interface rdb.
 */
void
dumpstack(void)
callwithureg(void (*fn)(Ureg*))
{
	Ureg ureg;
	ureg.pc = getcallerpc(&fn);
	ureg.sp = (ulong)&fn;
	fn(&ureg);
}

void
_dumpstack(Ureg *ureg)
{
	ulong l, v;
	int i;

	if(up == 0)
		return;

	print("ktrace /kernel/path %.8lux %.8lux\n", ureg->pc, ureg->sp);
	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);
			print("%.8lux=%.8lux ", l, v);
			if(i++ == 4){
				print("\n");
				i = 0;


@@ 454,6 440,12 @@ dumpstack(void)
}

void
dumpstack(void)
{
	callwithureg(_dumpstack);
}

void
dumpregs(Ureg *ur)
{
	int i;

M port/devcons.c => port/devcons.c +2 -1
@@ 632,6 632,7 @@ consopen(Chan *c, int omode)
			qnoblock(kprintoq, 1);
		}else
			qreopen(kprintoq);
		c->iounit = qiomaxatomic;
		break;
	}
	return c;


@@ 846,7 847,7 @@ consread(Chan *c, void *buf, long n, vlong off)
		return n;

	case Qosversion:
		snprint(tmp, sizeof tmp, "2000 %d", qiomaxatomic);
		snprint(tmp, sizeof tmp, "2000");
		n = readstr((ulong)offset, buf, n, tmp);
		return n;


M port/devdraw.c => port/devdraw.c +3 -2
@@ 37,6 37,7 @@ enum

#define	NHASH		(1<<5)
#define	HASHMASK	(NHASH-1)
#define	IOUNIT	(64*1024)

typedef struct Client Client;
typedef struct Draw Draw;


@@ 908,7 909,7 @@ drawopen(Chan *c, int omode)

	if(c->qid.type & QTDIR){
		c = devopen(c, omode, 0, 0, drawgen);
		c->iounit = 32*1024;
		c->iounit = IOUNIT;
	}

	qlock(&sdraw);


@@ 949,7 950,7 @@ drawopen(Chan *c, int omode)
	c->mode = openmode(omode);
	c->flag |= COPEN;
	c->offset = 0;
	c->iounit = 32*1024;
	c->iounit = IOUNIT;
	return c;
}


M port/devloopback.c => port/devloopback.c +1 -0
@@ 310,6 310,7 @@ loopbackopen(Chan *c, int omode)
	c->mode = openmode(omode);
	c->flag |= COPEN;
	c->offset = 0;
	c->iounit = qiomaxatomic;
	return c;
}


M port/devpipe.c => port/devpipe.c +1 -0
@@ 207,6 207,7 @@ pipeopen(Chan *c, int omode)
	c->mode = openmode(omode);
	c->flag |= COPEN;
	c->offset = 0;
	c->iounit = qiomaxatomic;
	return c;
}


M port/devtls.c => port/devtls.c +1 -0
@@ 481,6 481,7 @@ tlsopen(Chan *c, int omode)
	c->mode = openmode(omode);
	c->flag |= COPEN;
	c->offset = 0;
	c->iounit = qiomaxatomic;
	return c;
}


M port/devuart.c => port/devuart.c +1 -0
@@ 242,6 242,7 @@ uartopen(Chan *c, int omode)
		break;
	}

	c->iounit = qiomaxatomic;
	return c;
}


M port/netif.c => port/netif.c +1 -0
@@ 181,6 181,7 @@ netifopen(Netif *nif, Chan *c, int omode)
	c->mode = openmode(omode);
	c->flag |= COPEN;
	c->offset = 0;
	c->iounit = qiomaxatomic;
	return c;
}