~kris/9p

9hist

00226baff35ca72828ab9237da61a70a0c5f646d — David du Colombier 25 years ago c18632d
Plan 9 from Bell Labs 2000-10-12
10 files changed, 303 insertions(+), 47 deletions(-)

M bitsy/dat.h
M bitsy/l.s
M bitsy/main.c
M bitsy/mmu.c
M bitsy/trap.c
M ip/tcp.c
M pc/main.c
M pc/mouse.c
M port/devmouse.c
M port/segment.c
M bitsy/dat.h => bitsy/dat.h +7 -16
@@ 80,7 80,7 @@ enum

struct PMMU
{
	ulong	pid;		/* current pid (0 if none) */
	ulong	tlbpid;		/* current pid (0 if none) */
	Page	*l1[Nmeg];	/* this's process' level 1 entries */
};



@@ 114,6 114,7 @@ struct Mach

	ulong	fairness;		/* for runproc */

	/* stats */
	int	tlbfault;
	int	tlbpurge;
	int	pfault;


@@ 123,24 124,15 @@ struct Mach
	int	intr;
	vlong	fastclock;		/* last sampled value */
	vlong	intrts;			/* time stamp of last interrupt */
	int	flushmmu;		/* make current proc flush it's mmu state */

	ulong	spuriousintr;
	int	lastintr;

	int	loopconst;

	int	cpumhz;
	int	cpuhz;
	int	cpuidax;
	int	cpuiddx;
	char	cpuidid[16];
	char*	cpuidtype;
	int	flushmmu;		/* make current proc flush it's mmu state */
	Proc	*pid2proc[31];		/* what proc holds what pid */
	int	lastpid;		/* highest assigned pid slot */

	vlong	mtrrcap;
	vlong	mtrrdef;
	vlong	mtrrfix[11];
	vlong	mtrrvar[32];		/* 256 max. */
	int	cpumhz;			/* speed of cpu */
	int	cpuhz;			/* ... *

	/* save areas for exceptions */
	ulong	sfiq[5];


@@ 197,4 189,3 @@ enum
{
	OneMeg=	1024*1024,
};


M bitsy/l.s => bitsy/l.s +35 -3
@@ 173,8 173,8 @@ TEXT vtable(SB), $-4
	WORD	$_vsvc(SB)			/* reset, in svc mode already */
	WORD	$_vund(SB)			/* undefined, switch to svc mode */
	WORD	$_vsvc(SB)			/* swi, in svc mode already */
	WORD	$_vabt(SB)			/* prefetch abort, switch to svc mode */
	WORD	$_vabt(SB)			/* data abort, switch to svc mode */
	WORD	$_vpabt(SB)			/* prefetch abort, switch to svc mode */
	WORD	$_vdabt(SB)			/* data abort, switch to svc mode */
	WORD	$_vsvc(SB)			/* reserved */
	WORD	$_virq(SB)			/* IRQ, switch to svc mode */
	WORD	$_vfiq(SB)			/* FIQ, switch to svc mode */


@@ 208,11 208,16 @@ TEXT _vund(SB), $-4			/* undefined */
	MOVW	$PsrMund, R0
	B	_vswitch

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

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

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


@@ 277,6 282,33 @@ _userexcep:
TEXT _vfiq(SB), $-4			/* FIQ */
	RFE				/* FIQ is special, ignore it for now */

/*
 *  This is the first jump from kernel to user mode.
 *  Fake a return from interrupt.
 *
 *  Enter with R0 containing the user stack pointer.
 *  UTZERO + 0x20 is always the entry point.
 *  
 */
TEXT touser(SB),$-4
	/* store the user stack pointer into the USR_r13 */
	MOVM.DB.W [R0], (R13)
	MOVM.S.IA.W (R13),[R13]

	/* set up a PSR for user level */
	MOVW	$(PsrMusr), R0
	MOVW	R0,SPSR

	/* save the PC on the stack */
	MOVW	$(UTZERO+0x20), R0
	MOVM.DB.W [R0],(R13)

	/* return from interrupt */
	RFE				/* MOVM.IA.S.W (R13), [R15] */
	
/*
 *  here to jump to a newly forked process
 */
TEXT forkret(SB),$-4
	ADD	$(4*15), R13		/* make r13 point to ureg->type */
	MOVW	8(R13), R14		/* restore link */

M bitsy/main.c => bitsy/main.c +77 -3
@@ 13,6 13,8 @@ Conf conf;

static void	gpioinit(void);

int  noprint;

void
main(void)
{


@@ 21,6 23,7 @@ main(void)

	/* point to Mach structure */
	m = (Mach*)MACHADDR;
	memset(m, 0, sizeof(Mach));

	rs232power(1);
	iprint("bitsy kernel\n");


@@ 31,10 34,16 @@ main(void)
	sa1100_uartsetup();
	gpioinit();
	trapinit();
	printinit();
	clockinit();
	procinit0();
	initseg();
	chandevreset();
noprint = 1;
	pageinit();
	swapinit();
	userinit();
iprint("schedinit(), death soon\n");
	schedinit();
}



@@ 44,7 53,7 @@ main(void)
void
exit(int ispanic)
{
	void (*f)();
	void (*f)(void);

	USED(ispanic);
	delay(1000);


@@ 55,6 64,8 @@ exit(int ispanic)
	(*f)();
}

static uchar *sp;

/*
 *  starting place for first process
 */


@@ 87,7 98,66 @@ init0(void)
	}
	kproc("alarm", alarmkproc, 0);

	touser();
	touser(sp);
}

/*
 *  pass boot arguments to /boot
 */
static uchar *
pusharg(char *p)
{
	int n;

	n = strlen(p)+1;
	sp -= n;
	memmove(sp, p, n);
	return sp;
}
static void
bootargs(ulong base)
{
 	int i, ac;
	uchar *av[32];
	uchar *bootpath;
	uchar **lsp;

	/*
 	 *  the sizeof(Sargs) is to make the validaddr check in
	 *  trap.c's syscall() work even when we have less than the
	 *  max number of args.
	 */
	sp = (uchar*)base + BY2PG - sizeof(Sargs);

	bootpath = pusharg("/boot");
	ac = 0;
	av[ac++] = pusharg("boot");

	/* 4 byte word align stack */
	sp = (uchar*)((ulong)sp & ~3);

	/* build argc, argv on stack */
	sp -= (ac+1)*sizeof(sp);
	lsp = (uchar**)sp;
	for(i = 0; i < ac; i++)
		*lsp++ = av[i] + ((USTKTOP - BY2PG) - base);
	*lsp = 0;

	/* push argv onto stack */
	sp -= BY2WD;
	lsp = (uchar**)sp;
	*lsp = sp + BY2WD + ((USTKTOP - BY2PG) - base);

	/* push pointer to "/boot" */
	sp -= BY2WD;
	lsp = (uchar**)sp;
	*lsp = bootpath + ((USTKTOP - BY2PG) - base);

	/* leave space for where the initcode's caller's return PC would normally reside */
	sp -= BY2WD;

	/* relocate stack to user's virtual addresses */
	sp += (USTKTOP - BY2PG) - base;
}

/*


@@ 112,11 182,12 @@ userinit(void)
	strcpy(p->text, "*init*");
	strcpy(p->user, eve);


	/*
	 * Kernel Stack
	 */
	p->sched.pc = (ulong)init0;
	p->sched.sp = (ulong)p->kstack+KSTACK-(1+MAXSYSARG)*BY2WD;
	p->sched.sp = (ulong)p->kstack+KSTACK-(sizeof(Sargs)+BY2WD);

	/*
	 * User Stack


@@ 125,6 196,9 @@ userinit(void)
	p->seg[SSEG] = s;
	pg = newpage(1, 0, USTKTOP-BY2PG);
	segpage(s, pg);
	k = kmap(pg);
	bootargs(VA(k));
	kunmap(k);

	/*
	 * Text

M bitsy/mmu.c => bitsy/mmu.c +30 -10
@@ 100,11 100,9 @@ mmuinit(void)
	t[(a&0xfffff)>>PGSHIFT] = L2SmallPage | L2KernelRW | (PHYSDRAM0 & L2PageBaseMask);

	/* set up the domain register to cause all domains to obey pte access bits */
	iprint("setting up domain access\n");
	putdac(Dclient);

	/* point to map */
	iprint("setting tlb map %lux\n", (ulong)l1table);
	putttb((ulong)l1table);

	/* enable mmu */


@@ 196,14 194,34 @@ mapspecial(ulong pa, int len)
}

/*
 *  find a new pid.  If none exist, flush all pids, mmu, and caches.
 *  maintain pids
 */
static Lock pidlock;

void
flushpids(void)
{
	memset(l1table, 0, BY2WD*nelem(m->pid2proc)*32);
	memset(m->pid2proc, 0, sizeof(m->pid2proc));
	flushcache();
	flushmmu();
}

int
newtlbpid(Proc *p)
{
	return p->pid;
	int i;

	ilock(&pidlock);
	i = ++(m->lastpid);
	if(i >= nelem(m->pid2proc)){
		flushpids();
		i = m->lastpid = 0;
	}
	m->pid2proc[i] = p;
	p->tlbpid = i+1;
	iunlock(&pidlock);
	return p->tlbpid;
}

/*


@@ 232,9 250,10 @@ putmmu(ulong va, ulong pa, Page*)
	Page *p;
	ulong *t;

	/* if user memory, offset by pid value */
iprint("putmmu(0x%.8lux, 0x%.8lux)\n", va, pa);
	/* if user memory, add pid value */
	if((va & 0xfe000000) == 0)
		pva = va | (up->pid << 25);
		pva = va | (up->tlbpid << 25);
	else
		pva = va;



@@ 281,10 300,11 @@ void
mmuswitch(Proc* p)
{
	/* set pid */
	if(p->pid <= 0)
		p->pid = newtlbpid(p);
	putpid(p->pid<<25);
	if(p->tlbpid <= 0)
		p->tlbpid = newtlbpid(p);
iprint("using tlbpid %d\n", p->tlbpid);
	putpid(p->tlbpid<<25);

	/* set domain register to this + the kernel's domains */
	putdac((Dclient<<(2*p->pid)) | Dclient);
	putdac((Dclient<<(2*p->tlbpid)) | Dclient);
}

M bitsy/trap.c => bitsy/trap.c +98 -4
@@ 84,6 84,19 @@ trapdump(char *tag)
		intrregs->iccr, intrregs->icfp);
}

void
dumpregs(Ureg *ur)
{
	iprint("r0  0x%.8lux r1  0x%.8lux r3  0x%.8lux r3  0x%.8lux\n",
		ur->r0, ur->r1, ur->r2, ur->r3);
	iprint("r4  0x%.8lux r5  0x%.8lux r6  0x%.8lux r7  0x%.8lux\n",
		ur->r4, ur->r5, ur->r6, ur->r7);
	iprint("r8  0x%.8lux r9  0x%.8lux r10 0x%.8lux r11 0x%.8lux\n",
		ur->r8, ur->r9, ur->r10, ur->r11);
	iprint("r12 0x%.8lux r13 0x%.8lux r14 0x%.8lux\n",
		ur->r12, ur->r13, ur->r14);
	iprint("type %.8lux psr %.8lux pc %.8lux\n", ur->type, ur->psr, ur->pc);
}

/*
 *  enable an interrupt and attach a function to it


@@ 108,6 121,31 @@ intrenable(int irq, void (*f)(Ureg*, void*), void* a, char *name)
}

/*
 *  called by trap to handle access faults
 */
static void
faultarm(Ureg *ureg, ulong va, int user, int read)
{
	int n, insyscall;
	char buf[ERRLEN];

	insyscall = up->insyscall;
	up->insyscall = 1;
	n = fault(va, read);
iprint("fault returns %d\n", n);
	if(n < 0){
		if(!user){
			dumpregs(ureg);
			panic("fault: 0x%lux\n", va);
		}
		sprint(buf, "sys: trap: fault %s va=0x%lux",
			read? "read" : "write", va);
		postnote(up, 1, buf, NDebug);
	}
	up->insyscall = insyscall;
}

/*
 *  here on all exceptions other than syscall (SWI)
 */
void


@@ 115,15 153,66 @@ trap(Ureg *ureg)
{
	int i;
	Vctl *v;
	int user;
	ulong pc, va;
	char buf[ERRLEN];

	iprint("trap %lux pc %lux psr %lux\n", ureg->type, ureg->pc, ureg->psr);

	user = (ureg->psr & PsrMask) == PsrMusr;
	switch(ureg->type){
	default:
		panic("unknown trap");
		break;
	case PsrMabt:	/* fault */
		panic("faults not implemented");
	case PsrMabt:	/* prefetch fault */
		iprint("prefetch abort at %lux\n", ureg->pc-4);
		faultarm(ureg, ureg->pc - 4, user, 1);
		break;
	case PsrMabt+1:	/* data fault */
		pc = ureg->pc - 8;
		va = getfar();
		switch(getfsr() & 0xf){
		case 0x0:
			panic("vector exception at %lux\n", pc);
			break;
		case 0x1:
		case 0x3:
			if(user){
				snprint(buf, sizeof(buf), "sys: alignment: pc 0x%lux va 0x%lux\n",
					pc, va);
				postnote(up, 1, buf, NDebug);
			} else
				panic("kernel alignment: pc 0x%lux va 0x%lux", pc, va);
			break;
		case 0x2:
			panic("terminal exception at %lux\n", pc);
			break;
		case 0x4:
		case 0x6:
		case 0x8:
		case 0xa:
		case 0xc:
		case 0xe:
			panic("external abort at %lux\n", pc);
			break;
		case 0x5:
		case 0x7:
			/* translation fault, i.e., no pte entry */
			faultarm(ureg, va, user, 0);
			break;
		case 0x9:
		case 0xb:
			/* domain fault, accessing something we shouldn't */
			if(user){
				sprint(buf, "sys: access violation: pc 0x%lux va 0x%lux\n", pc, va);
				postnote(up, 1, buf, NDebug);
			} else
				panic("kernel access violation: pc 0x%lux va 0x%lux\n", pc, va);
			break;
		case 0xd:
		case 0xf:
			/* permission error, copy on write or real permission error */
			faultarm(ureg, va, user, 1);
			break;
		}
		break;
	case PsrMund:	/* undefined instruction */
		panic("undefined instruction");


@@ 137,6 226,11 @@ trap(Ureg *ureg)
			}
		break;
	}

	if(user && (up->procctl || up->nnote)){
		splhi();
		notify(ureg);
	}
}

/*

M ip/tcp.c => ip/tcp.c +6 -0
@@ 1820,6 1820,12 @@ tcpoutput(Conv *s)
			x = backoff(tcb->backoff) *
			    (tcb->mdev + (tcb->srtt>>LOGAGAIN) + MSPTICK) / MSPTICK;

			/*  allow for slow initial response
			 *  (miller@hamnavoe.demon.co.uk)
			 */
			if(tcb->state == Syn_sent && x < 500/MSPTICK)
				x = 500/MSPTICK;

			/* take into account delayed ack */
			if(sent <= 2*tcb->mss)
				x += TCP_ACK/MSPTICK;

M pc/main.c => pc/main.c +3 -2
@@ 249,11 249,12 @@ userinit(void)
	/*
	 * Kernel Stack
	 *
	 * N.B. The -12 for the stack pointer is important.
	 * N.B. make sure there's enough space for syscall to check
	 *	for valid args and 
	 *	4 bytes for gotolabel's return PC
	 */
	p->sched.pc = (ulong)init0;
	p->sched.sp = (ulong)p->kstack+KSTACK-(1+MAXSYSARG)*BY2WD;
	p->sched.sp = (ulong)p->kstack+KSTACK-(sizeof(Sargs)+BY2WD);

	/*
	 * User Stack

M pc/mouse.c => pc/mouse.c +42 -7
@@ 22,6 22,10 @@ enum
	MousePS2=	2,
};
static int mousetype;
static int intellimouse;
static int packetsize;
static int resolution;
static int accelerated;

/*
 *  setup a serial mouse


@@ 43,6 47,7 @@ serialmouse(int port, char *type, int setspeed)
	else
		ns16552special(port, setspeed, 0, 0, mouseputc);
	mousetype = Mouseserial;
	packetsize = 3;
}

/*


@@ 53,11 58,22 @@ serialmouse(int port, char *type, int setspeed)
 *	byte 2 -	DY
 *
 *  shift & right button is the same as middle button
 *
 * Intellimouse and AccuPoint with extra buttons deliver
 *	byte 3 -	00 or 01 or FF according to extra button state.
 * extra buttons are mapped in this code to buttons 4 and 5.
 * AccuPoint generates repeated events for these buttons;
*  it and Intellimouse generate 'down' events only, so
 * user-level code is required to generate button 'up' events
 * if they are needed by the application.
 * Also on laptops with AccuPoint AND external mouse, the
 * controller may deliver 3 or 4 bytes according to the type
 * of the external mouse; code must adapt.
 */
static void
ps2mouseputc(int c, int shift)
{
	static short msg[3];
	static short msg[4];
	static int nb;
	static uchar b[] = {0, 1, 4, 5, 2, 3, 6, 7, 0, 1, 2, 3, 2, 3, 6, 7 };
	int buttons, dx, dy;


@@ 66,10 82,14 @@ ps2mouseputc(int c, int shift)
	 *  check byte 0 for consistency
	 */
	if(nb==0 && (c&0xc8)!=0x08)
		return;
		if(intellimouse && (c==0x00 || c==0x01 || c==0xFF)){
			/* last byte of 4-byte packet */
			packetsize = 4;
			return;
		}

	msg[nb] = c;
	if(++nb == 3){
	if(++nb == packetsize){
		nb = 0;
		if(msg[0] & 0x10)
			msg[1] |= 0xFF00;


@@ 77,6 97,22 @@ ps2mouseputc(int c, int shift)
			msg[2] |= 0xFF00;

		buttons = b[(msg[0]&7) | (shift ? 8 : 0)];
		if(intellimouse && packetsize==4){
			if((msg[3]&0xc8) == 0x08){
				/* first byte of 3-byte packet */
				packetsize = 3;
				msg[0] = msg[3];
				nb = 1;
				/* fall through to emit previous packet */
			}else{
				/* the AccuPoint on the Toshiba 34[48]0CT encodes extra buttons as 4 and 5 */
				/* they repeat and don't release, however, so user-level timing code is required */
				if(msg[3] == 0xFF) 
					buttons |= 1<<3;
				if(msg[3] == 0x01) 
					buttons |= 1<<4;
			}
		}
		dx = msg[1];
		dy = -msg[2];
		mousetrack(buttons, dx, dy);


@@ 99,12 135,9 @@ ps2mouse(void)
	i8042auxcmd(0xF4);

	mousetype = MousePS2;
	packetsize = 3;
}

static int intellimouse;
static int resolution;
static int accelerated;

static void
setaccelerated(int x)
{


@@ 149,6 182,7 @@ static void
setintellimouse(void)
{
	intellimouse = 1;
	packetsize = 4;
	switch(mousetype){
	case MousePS2:
		i8042auxcmd(0xF3);	/* set sample */


@@ 164,6 198,7 @@ setintellimouse(void)
static void
resetmouse(void)
{
	packetsize = 3;
	switch(mousetype){
	case MousePS2:
		i8042auxcmd(0xF6);

M port/devmouse.c => port/devmouse.c +5 -1
@@ 199,6 199,7 @@ mouseread(Chan *c, void *va, long n, vlong off)
	static int map[8] = {0, 4, 2, 6, 1, 5, 3, 7 };
	ulong offset = off;
	Mousestate m;
	int b;

	p = va;
	switch(c->qid.path){


@@ 245,9 246,12 @@ mouseread(Chan *c, void *va, long n, vlong off)
			unlock(&cursor);
		}

		b = buttonmap[m.buttons&7];
		/* put buttons 4 and 5 back in */
		b |= m.buttons & (3<<3);
		sprint(buf, "m%11d %11d %11d %11lud",
			m.xy.x, m.xy.y,
			buttonmap[m.buttons&7],
			b,
			m.msec);
		mouse.lastcounter = m.counter;
		if(n > 1+4*12)

M port/segment.c => port/segment.c +0 -1
@@ 55,7 55,6 @@ newseg(int type, ulong base, ulong size)

	if(swapfull())
		error(Enoswap);

	s = smalloc(sizeof(Segment));
	s->ref = 1;
	s->type = type;