~kris/9p

9hist

5d2460d6d8ad170beaceb3626ff3fb85684da42c — David du Colombier 25 years ago 810ca0f
Plan 9 from Bell Labs 2000-10-02
5 files changed, 423 insertions(+), 59 deletions(-)

M bitsy/devuart.c
M bitsy/fns.h
M bitsy/l.s
M bitsy/mmu.c
M bitsy/trap.c
M bitsy/devuart.c => bitsy/devuart.c +71 -3
@@ 133,6 133,10 @@ static int uartndir;
static char	Ekinuse[] = "device in use by kernel";

static void	uartsetbaud(Uart *p, int rate);
static void	uartflow(void *v);
static void	uartkick0(void *v);
static void	uartkick(void *v);
static void	uartrts(Uart *p, int on);

/*
 *  define a Uart.


@@ 149,7 153,6 @@ uartsetup(Uartregs *regs, ulong freq, char *name)
	uart[nuart] = p;
	strcpy(p->name, name);
	p->dev = nuart++;
	p->port = port;
	p->freq = freq;
	p->regs = regs;



@@ 232,8 235,6 @@ uartreset(void)
	int i;
	Dirtab *dp;

	uartsetup(uart3regs, ;

	uartndir = 3*nuart;
	uartdir = xalloc(uartndir * sizeof(Dirtab));
	dp = uartdir;


@@ 522,6 523,9 @@ Dev uartdevtab = {
	uartwstat,
};

/*
 *  set the buad rate
 */
static void
uartsetbaud(Uart *p, int rate)
{


@@ 537,6 541,70 @@ uartsetbaud(Uart *p, int rate)
	p->baud = rate;
}

/*
 *  turn on/off rts
 */
static void
uartrts(Uart *p, int on)
{
}

/*
 *  restart input if it's off
 */
static void
uartflow(void *v)
{
	Uart *p;

	p = v;
	if(p->modem){
		uartrts(p, 1);
		ilock(&p->rlock);
		p->haveinput = 1;
		iunlock(&p->rlock);
	}
}

/*
 *  restart output if not blocked and OK to send
 */
static void
uartkick0(void *v)
{
	int i;
	Uart *p;

	p = v;
	if(p->cts == 0 || p->blocked)
		return;

	/*
	 *  128 here is an arbitrary limit to make sure
	 *  we don't stay in this loop too long.  If the
	 *  chips output queue is longer than 128, too
	 *  bad -- presotto
	 */
	for(i = 0; i < 128; i++){
//		if(!(uartrdreg(p, Lstat) & Outready))
//			break;
//		if(p->op >= p->oe && stageoutput(p) == 0)
//			break;
//		outb(p->port + Data, *(p->op++));
	}
}

static void
uartkick(void *v)
{
	Uart *p;

	p = v;
	ilock(&p->tlock);
	uartkick0(p);
	iunlock(&p->tlock);
}

void
serialputs(char *str, int n)
{

M bitsy/fns.h => bitsy/fns.h +4 -1
@@ 15,17 15,20 @@ ulong	getfsr(void);
void	idle(void);
#define	idlehands()			/* nothing to do in the runproc */
int	iprint(char*, ...);
ulong*	mapspecial(ulong, int);
void*	mapspecial(ulong, int);
void	meminit(void);
void	mmuinit(void);
void	mmuenable(void);
void	mmudisable(void);
void	noted(Ureg*, ulong);
int	notify(Ureg*);
#define	procrestore(p)
void	procsave(Proc*);
void	procsetup(Proc*);
void	putdac(ulong);
void	putttb(ulong);
void	putpid(ulong);
void	reset(void);
void	screeninit(void);
int	screenprint(char*, ...);			/* debugging */
void	(*screenputs)(char*, int);

M bitsy/l.s => bitsy/l.s +62 -36
@@ 153,40 153,49 @@ TEXT exceptionvectors(SB), $-4
	WORD	$_vfiq(SB)		/* FIQ, switch to svc mode */

TEXT _vrst(SB), $-4
	BL	reset
	BL	reset(SB)

TEXT _vsvc(SB), $-4			/* SWI */
	SUB	$12, R13		/* make room for pc, psr, & type */
	MOVW	R14, 8(R13)		/* ureg->pc = interupted PC */
	MOVW.DB.W R14, (R13)		/* ureg->pc = interupted PC */
	MOVW	SPSR, R14		/* ureg->psr = SPSR */
	MOVW	R14, 4(R13)		/* ... */
	MOVW.DB.W R14, (R13)		/* ... */
	MOVW	$PsrMsvc, R14		/* ureg->type = PsrMsvc */
	MOVW	R14, (R13)		/* ... */
	MOVW.DB.W R14, (R13)		/* ... */
	MOVM.DB.W.S [R0-R14], (R13)	/* save user level registers, at end r13 points to ureg */
	B	_vexcep			/* call the exception handler */
	MOVW	$setR12(SB), R12	/* Make sure we've got the kernel's SB loaded */
	MOVW	R13, R0			/* first arg is pointer to ureg */
	SUB	$8, R13			/* space for argument+link */

	BL	syscall(SB)

	ADD	$(8+4*15), R13		/* make r13 point to ureg->type */
	MOVW	8(R13), R14		/* restore link */
	MOVW	4(R13), R0		/* restore SPSR */
	MOVW	R0, SPSR		/* ... */
	MOVM.DB.S (R13), [R0-R14]	/* restore registers */
	ADD	$8, R13			/* pop past ureg->{type+psr} */
	RFE				/* MOVM.IA.S.W (R13), [R15] */

TEXT _vund(SB), $-4			/* undefined */
	MOVM.IA	[R0-R3], (R13)		/* free some working space */
	MOVM.IA	[R0-R4], (R13)		/* free some working space */
	MOVW	$PsrMund, R0
	B	_vswitch

TEXT _vabt(SB), $-4			/* prefetch abort */
	MOVM.IA	[R0-R3], (R13)		/* free some working space */
	MOVM.IA	[R0-R4], (R13)		/* free some working space */
	MOVW	$PsrMabt, R0		/* r0 = type */
	B	_vswitch

TEXT _virq(SB), $-4			/* IRQ */
	MOVM.IA	[R0-R3], (R13)		/* free some working space */
	MOVM.IA	[R0-R4], (R13)		/* free some working space */
	MOVW	$PsrMirq, R0		/* r0 = type */
	B	_vswitch

TEXT _vfiq(SB), $-4			/* FIQ */
	RFE				/* RIQ is special, ignore it for now */

	/*
	 *  come here with type in R0 and R13 pointing above saved [r0-r3]
	 *  come here with type in R0 and R13 pointing above saved [r0-r4]
	 *  and type in r0.  we'll switch to SVC mode and then call trap.
	 */
_vswitch:				/* switch to svc, type in R0 */
_vswitch:
	MOVW	SPSR, R1		/* save SPSR for ureg */
	MOVW	R14, R2			/* save interrupted pc for ureg */
	MOVW	R13, R3			/* save pointer to where the original [R0-R3] are */


@@ 197,39 206,56 @@ _vswitch:				/* switch to svc, type in R0 */
	ORR	$(PsrDirq|PsrDfiq|PsrMsvc), R14
	MOVW	R14, CPSR

	/*
	 *  R13 and R14 is now R13_SVC and R14_SVC.  The values of the previous mode's
	 *  R13 and R14 are no longer accessible.  That's why R3 was left to point to where
	 *  the old [r0-r3] are stored.
	 */
	/* interupted code kernel or user? */
	AND.S	$0xf, R1, R4
	B.EQ	_userexcep

	/* here for trap from SVC mode */
	MOVM.DB.W [R0-R2], (R13)	/* set ureg->{type, psr, pc}; r13 points to ureg->type  */
	MOVM.IA	  (R3), [R0-R3]		/* restore [R0-R3] from previous mode's stack */
	MOVM.DB.W.S [R0-R14], (R13)	/* save user level registers, at end r13 points to ureg */
	MOVM.IA	  (R3), [R0-R4]		/* restore [R0-R4] from previous mode's stack */
	MOVM.DB.W [R0-R14], (R13)	/* save kernel level registers, at end r13 points to ureg */
	MOVW	$setR12(SB), R12	/* Make sure we've got the kernel's SB loaded */
	MOVW	R13, R0			/* first arg is pointer to ureg */
	SUB	$8, R13			/* space for argument+link (for debugger) */

	/*
	 *  if the original interrupt happened while executing SVC mode,
	 *  the User R14 in the Ureg is wrong.  We need to save the SVC one there.
	 */
	MOVW	0x40(R13), R1
	AND.S	$0xf, R1
	MOVW.NE	R14,0x38(R13)
	B	_vexcep
	BL	trap(SB)

	/*
 	 *  call the exception routine, the ureg is at the bottom of the stack
	 */
_vexcep:
	ADD	$(8+4*15), R13		/* make r13 point to ureg->type */
	MOVW	8(R13), R14		/* restore link */
	MOVW	4(R13), R0		/* restore SPSR */
	MOVW	R0, SPSR		/* ... */
	MOVM.DB (R13), [R0-R14]	/* restore registers */
	ADD	$8, R13			/* pop past ureg->{type+psr} */
	RFE				/* MOVM.IA.S.W (R13), [R15] */

	/* here for trap from USER mode */
_userexcep:
	MOVM.DB.W [R0-R2], (R13)	/* set ureg->{type, psr, pc}; r13 points to ureg->type  */
	MOVM.IA	  (R3), [R0-R4]		/* restore [R0-R4] from previous mode's stack */
	MOVM.DB.W.S [R0-R14], (R13)	/* save kernel level registers, at end r13 points to ureg */
	MOVW	$setR12(SB), R12	/* Make sure we've got the kernel's SB loaded */
	MOVW	R13, R0			/* first arg is pointer to ureg */
	SUB	$8, R13			/* space for argument+link */
	SUB	$8, R13			/* space for argument+link (for debugger) */

	BL	trap(SB)

_vrfe: 
	ADD	$(8+4*15), R13		/* make r13 point to ureg->type */
	MOVW	8(R13), R14		/* restore link */
	MOVW	4(R13), R0		/* restore SPSR */
	MOVW	R0, SPSR		/* ... */
	MOVM.DB.W.S (R13), [R0-R14]	/* restore registers */
	MOVM.DB.S (R13), [R0-R14]	/* restore registers */
	ADD	$8, R13			/* pop past ureg->{type+psr} */
	RFE				/* MOVM.IA.S.W (R13), [R15] */

TEXT _vfiq(SB), $-4			/* FIQ */
	RFE				/* FIQ is special, ignore it for now */

TEXT forkret(SB),$-4
	ADD	$(4*15), R13		/* make r13 point to ureg->type */
	MOVW	8(R13), R14		/* restore link */
	MOVW	4(R13), R0		/* restore SPSR */
	MOVW	R0, SPSR		/* ... */
	MOVM.DB.S (R13), [R0-R14]	/* restore registers */
	ADD	$8, R13			/* pop past ureg->{type+psr} */
	RFE				/* MOVM.IA.S.W (R13), [R15] */


M bitsy/mmu.c => bitsy/mmu.c +2 -2
@@ 98,7 98,7 @@ mmuinit(void)
	putttb((ulong)l1table);

	/* map the uart so that we can continue using iprint */
	uart3regs = (Uartregs*)mapspecial(UART3REGS, 64);
	uart3regs = mapspecial(UART3REGS, 64);

	/* enable mmu, and make 0xFFFF0000 the virtual address of the exception vecs */
	mmuenable();


@@ 109,7 109,7 @@ mmuinit(void)
/*
 *  map special space uncached, assume that the space isn't already mapped
 */
ulong*
void*
mapspecial(ulong pa, int len)
{
	ulong *t;

M bitsy/trap.c => bitsy/trap.c +284 -17
@@ 14,7 14,7 @@ struct Intrregs
	ulong	iclr;	/* IRQ if bit == 0, FRIQ if 1 */
	ulong	iccr;	/* control register */
	ulong	icfp;	/* pending FIQs */
	ulong	dummy1[3]
	ulong	dummy1[3];
	ulong	icpr;	/* pending interrupts */
	
};


@@ 54,18 54,17 @@ trapinit(void)
	/* map in interrupt registers */
	intrregs = mapspecial(INTRREGS, sizeof(*intrregs));

	/* make all interrupts irq and disable all interrupts */
	/* make all interrupts IRQ (i.e. not FIQ) and disable all interrupts */
	intrregs->iclr = 0;
	intrregs->icmr = 0;
}

/*
 *  enable an interrupt and attach a function to i
 *  enable an interrupt and attach a function to it
 */
void
intrenable(int irq, void (*f)(Ureg*, void*), void* a, char *name)
{
	int vno;
	Vctl *v;

	v = xalloc(sizeof(Vctl));


@@ 78,21 77,21 @@ intrenable(int irq, void (*f)(Ureg*, void*), void* a, char *name)
	lock(&vctllock);
	v->next = vctl[irq];
	vctl[irq] = v;
	intrregs->icmr |= 1<<irq;
	unlock(&vctllock);
}

/*
 *  here on all exceptions with registers saved
 *  here on all exceptions other than syscall (SWI)
 */
void
trap(Ureg *ureg)
{
	switch(ureg->type){
	case PsrMfiq:	/* fast interrupt */
		panic("fiq can't happen");
	default:
		panic("unknown trap");
		break;
	case PsrMabt:	/* fault */
	case PsrMabt+1:	/* fault */
		panic("faults not implemented");
		break;
	case PsrMund:	/* undefined instruction */


@@ 100,18 99,243 @@ trap(Ureg *ureg)
		break;
	case PsrMirq:	/* device interrupt */
		break;
	case PsrMsvc:	/* system call */
	}
}

/*
 *  system calls
 */
#include "../port/systab.h"

/*
 *  Syscall is called directly from assembler without going through trap().
 */
void
syscall(Ureg* ureg)
{
	ulong	sp;
	long	ret;
	int	i, scallnr;

	if((ureg->psr & PsrMask) != PsrMusr)
		panic("syscall: cs 0x%4.4uX\n", ureg->psr);

	m->syscall++;
	up->insyscall = 1;
	up->pc = ureg->pc;
	up->dbgreg = ureg;

	scallnr = ureg->r0;
	up->scallnr = scallnr;
	spllo();

	sp = ureg->sp;
	up->nerrlab = 0;
	ret = -1;
	if(!waserror()){
		if(scallnr >= nsyscall){
			pprint("bad sys call number %d pc %lux\n",
				scallnr, ureg->pc);
			postnote(up, 1, "sys: bad sys call", NDebug);
			error(Ebadarg);
		}

		if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-sizeof(Sargs)-BY2WD))
			validaddr(sp, sizeof(Sargs)+BY2WD, 0);

		up->s = *((Sargs*)(sp+BY2WD));
		up->psstate = sysctab[scallnr];

		ret = systab[scallnr](up->s.args);
		poperror();
	}
	if(up->nerrlab){
		print("bad errstack [%d]: %d extra\n", scallnr, up->nerrlab);
		for(i = 0; i < NERR; i++)
			print("sp=%lux pc=%lux\n",
				up->errlab[i].sp, up->errlab[i].pc);
		panic("error stack");
	}

	up->insyscall = 0;
	up->psstate = 0;

	/*
	 *  Put return value in frame.  On the x86 the syscall is
	 *  just another trap and the return value from syscall is
	 *  ignored.  On other machines the return value is put into
	 *  the results register by caller of syscall.
	 */
	ureg->r0 = ret;

	if(scallnr == NOTED)
		noted(ureg, *(ulong*)(sp+BY2WD));

	if(scallnr != RFORK && (up->procctl || up->nnote)){
		splhi();
		notify(ureg);
	}
}

/*
 *   Return user to state before notify()
 */
void
noted(Ureg* ureg, ulong arg0)
{
	Ureg *nureg;
	ulong oureg, sp;

	qlock(&up->debug);
	if(arg0!=NRSTR && !up->notified) {
		qunlock(&up->debug);
		pprint("call to noted() when not notified\n");
		pexit("Suicide", 0);
	}
	up->notified = 0;

	nureg = up->ureg;	/* pointer to user returned Ureg struct */

	/* sanity clause */
	oureg = (ulong)nureg;
	if(!okaddr((ulong)oureg-BY2WD, BY2WD+sizeof(Ureg), 0)){
		pprint("bad ureg in noted or call to noted when not notified\n");
		qunlock(&up->debug);
		pexit("Suicide", 0);
	}

	/* don't let user change system flags */
	nureg->psr = (ureg->psr & ~(PsrMask|PsrDfiq|PsrDirq)) |
			(nureg->psr & (PsrMask|PsrDfiq|PsrDirq));

	memmove(ureg, nureg, sizeof(Ureg));

	switch(arg0){
	case NCONT:
	case NRSTR:
		if(!okaddr(nureg->pc, 1, 0) || !okaddr(nureg->sp, BY2WD, 0)){
			qunlock(&up->debug);
			pprint("suicide: trap in noted\n");
			pexit("Suicide", 0);
		}
		up->ureg = (Ureg*)(*(ulong*)(oureg-BY2WD));
		qunlock(&up->debug);
		break;

	case NSAVE:
		if(!okaddr(nureg->pc, BY2WD, 0)
		|| !okaddr(nureg->sp, BY2WD, 0)){
			qunlock(&up->debug);
			pprint("suicide: trap in noted\n");
			pexit("Suicide", 0);
		}
		qunlock(&up->debug);
		sp = oureg-4*BY2WD-ERRLEN;
		splhi();
		ureg->sp = sp;
		((ulong*)sp)[1] = oureg;	/* arg 1 0(FP) is ureg* */
		((ulong*)sp)[0] = 0;		/* arg 0 is pc */
		break;

	default:
		pprint("unknown noted arg 0x%lux\n", arg0);
		up->lastnote.flag = NDebug;
		/* fall through */
		
	case NDFLT:
		if(up->lastnote.flag == NDebug){ 
			qunlock(&up->debug);
			pprint("suicide: %s\n", up->lastnote.msg);
		} else
			qunlock(&up->debug);
		pexit(up->lastnote.msg, up->lastnote.flag!=NDebug);
	}
}

/*
 *  Call user, if necessary, with note.
 *  Pass user the Ureg struct and the note on his stack.
 */
int
notify(Ureg* ureg)
{
	int l;
	ulong s, sp;
	Note *n;

	if(up->procctl)
		procctl(up);
	if(up->nnote == 0)
		return 0;

	s = spllo();
	qlock(&up->debug);
	up->notepending = 0;
	n = &up->note[0];
	if(strncmp(n->msg, "sys:", 4) == 0){
		l = strlen(n->msg);
		if(l > ERRLEN-15)	/* " pc=0x12345678\0" */
			l = ERRLEN-15;
		sprint(n->msg+l, " pc=0x%.8lux", ureg->pc);
	}

	if(n->flag!=NUser && (up->notified || up->notify==0)){
		if(n->flag == NDebug)
			pprint("suicide: %s\n", n->msg);
		qunlock(&up->debug);
		pexit(n->msg, n->flag!=NDebug);
	}

	if(up->notified) {
		qunlock(&up->debug);
		splhi();
		return 0;
	}
		
	if(!up->notify){
		qunlock(&up->debug);
		pexit(n->msg, n->flag!=NDebug);
	}
	sp = ureg->sp;
	sp -= sizeof(Ureg);

	if(!okaddr((ulong)up->notify, 1, 0)
	|| !okaddr(sp-ERRLEN-4*BY2WD, sizeof(Ureg)+ERRLEN+4*BY2WD, 1)){
		pprint("suicide: bad address in notify\n");
		qunlock(&up->debug);
		pexit("Suicide", 0);
	}

	up->ureg = (void*)sp;
	memmove((Ureg*)sp, ureg, sizeof(Ureg));
	*(Ureg**)(sp-BY2WD) = up->ureg;	/* word under Ureg is old up->ureg */
	up->ureg = (void*)sp;
	sp -= BY2WD+ERRLEN;
	memmove((char*)sp, up->note[0].msg, ERRLEN);
	sp -= 3*BY2WD;
	*(ulong*)(sp+2*BY2WD) = sp+3*BY2WD;	/* arg 2 is string */
	*(ulong*)(sp+1*BY2WD) = (ulong)up->ureg;	/* arg 1 is ureg* */
	*(ulong*)(sp+0*BY2WD) = 0;		/* arg 0 is pc */
	ureg->sp = sp;
	ureg->pc = (ulong)up->notify;
	up->notified = 1;
	up->nnote--;
	memmove(&up->lastnote, &up->note[0], sizeof(Note));
	memmove(&up->note[0], &up->note[1], up->nnote*sizeof(Note));

	qunlock(&up->debug);
	splx(s);
	return 1;
}

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

/*


@@ 120,7 344,10 @@ setkernur(Ureg *ureg, Proc *p)
ulong
userpc(void)
{
	return 0;
	Ureg *ureg;

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

/* This routine must save the values of registers the user is not permitted


@@ 135,8 362,7 @@ setregisters(Ureg* ureg, char* pureg, char* uva, int n)
/*
 *  this is the body for all kproc's
 */
static
void
static void
linkproc(void)
{
	spllo();


@@ 166,7 392,20 @@ kprocchild(Proc *p, void (*func)(void*), void *arg)
void
forkchild(Proc *p, Ureg *ureg)
{
	USED(p, ureg);
	Ureg *cureg;

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

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

	/* syscall returns 0 for child */
	cureg->r0 = 0;

	/* Things from bottom of syscall which were never executed */
	p->psstate = 0;
	p->insyscall = 0;
}

/*


@@ 195,10 434,38 @@ dumpstack(void)
{
}


/*
 *  pc output by ps
 */
ulong
dbgpc(Proc *p)
{
	USED(p);
	return 0;
	Ureg *ureg;

	ureg = p->dbgreg;
	if(ureg == 0)
		return 0;

	return ureg->pc;
}

/*
 * called in sysfile.c
 */
void
evenaddr(ulong addr)
{
	if(addr & 3){
		postnote(up, 1, "sys: odd address", NDebug);
		error(Ebadarg);
	}
}


/*
 *  here on a hardware reset
 */
void
reset(void)
{
}