~kris/9p

9hist

51b7b955243a05c2c48c39f8ce3617f30a622771 — David du Colombier 33 years ago 1ff4ef2
Plan 9 from Bell Labs 1993-09-03
A carrera/clock.c => carrera/clock.c +100 -0
@@ 0,0 1,100 @@
#include	"u.h"
#include	"../port/lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"io.h"

#include	"ureg.h"

/*
 *  delay for l milliseconds more or less.  delayloop is set by
 *  clockinit() to match the actual CPU speed.
 */
void
delay(int l)
{
	ulong i, j;

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

void
clockinit(void)
{
	long x;

	m->delayloop = m->speed*100;
	do {
		x = rdcount();
		delay(10);
		x = rdcount() - x;
	} while(x < 0);

	/*
	 *  fix count
	 */
	m->delayloop = (m->delayloop*m->speed*1000*10)/x;
	if(m->delayloop == 0)
		m->delayloop = 1;

	wrcompare(rdcount()+(m->speed*1000000)/HZ);
}

void
clock(Ureg *ur)
{
	Proc *p;
	int i, nrun;

	wrcompare(rdcount()+(m->speed*1000000)/HZ);

	m->ticks++;
	if(m->proc)
		m->proc->pc = ur->pc;

	nrun = 0;
	if(m->machno == 0) {
		p = m->proc;
		if(p) {
			nrun++;
			p->time[p->insyscall]++;
		}
		for(i=1; i<conf.nmach; i++) {
			if(active.machs & (1<<i)) {
				p = MACHP(i)->proc;
				if(p) {
					p->time[p->insyscall]++;
					nrun++;
				}
			}
		}
		nrun = (nrdy+nrun)*1000;
		m->load = (m->load*19+nrun)/20;
	}

	kmapinval();

	if((active.machs&(1<<m->machno)) == 0)
		return;

	if(active.exiting && (active.machs & (1<<m->machno))) {
		print("someone's exiting\n");
		exit(0);
	}

	checkalarms();

	if(up == 0 || (ur->status&IE) == 0 || up->state != Running)
		return;

	if(anyready())
		sched(); /**/

	/* user profiling clock */
	if(ur->status & KUSER)
		(*(ulong*)(USTKTOP-BY2WD)) += TK2MS(1);	
}

A carrera/dat.h => carrera/dat.h +169 -0
@@ 0,0 1,169 @@
typedef struct Conf	Conf;
typedef struct FPsave	FPsave;
typedef struct Cycmsg	Cycmsg;
typedef struct KMap	KMap;
typedef struct Lance	Lance;
typedef struct Lancemem	Lancemem;
typedef struct Label	Label;
typedef struct Lock	Lock;
typedef struct Mach	Mach;
typedef struct MMU	MMU;
typedef struct PMMU	PMMU;
typedef struct Softtlb	Softtlb;
typedef struct Ureg	Ureg;

/*
 *  parameters for sysproc.c
 */
#define AOUT_MAGIC	V_MAGIC

/*
 *  machine dependent definitions used by ../port/dat.h
 */

struct Lock
{
	ulong	key;			/* semaphore (non-zero = locked) */
	ulong	pc;
	void	*upa;
};

struct Label
{
	ulong	sp;
	ulong	pc;
};

struct Conf
{
	ulong	nmach;		/* processors */
	ulong	nproc;		/* processes */
	ulong	npage0;		/* total physical pages of memory */
	ulong	npage1;		/* total physical pages of memory */
	ulong	npage;		/* total physical pages of memory */
	ulong	upages;		/* user page pool */
	ulong	nimage;		/* number of page cache image headers */
	ulong	nswap;		/* number of swap pages */
	ulong	base0;		/* base of bank 0 */
	ulong	base1;		/* base of bank 1 */
	ulong	copymode;	/* 0 is copy on write, 1 is copy on reference */
	ulong	ipif;		/* Ip protocol interfaces */
	ulong	ip;		/* Ip conversations per interface */
	ulong	arp;		/* Arp table size */
	ulong	frag;		/* Ip fragment assemble queue size */
	ulong	debugger;	/* use processor 1 as a kernel debugger */
};

/*
 * floating point registers
 */
enum
{
	FPinit,
	FPactive,
	FPinactive,
};

struct	FPsave
{
	long	fpreg[32];
	long	fpstatus;
};

/*
 *  mmu goo in the Proc structure
 */
struct PMMU
{
	int	pidonmach[MAXMACH];
	/*
	 * I/O point for hotrod interfaces.
	 * This is the easiest way to allocate
	 * them, but not the prettiest or most general.
	 */
	Cycmsg	*kcyc;
	Cycmsg	*ucyc;
	Cycmsg	*fcyc;
};

#include "../port/portdat.h"

struct Cycmsg
{
	ulong	cmd;
	ulong	param[5];
	Rendez	r;
	uchar	intr;			/* flag: interrupt has occurred */
};

/* First FOUR members offsets known by l.s */
struct Mach
{
	/* the following are all known by l.s and cannot be moved */
	int	machno;			/* physical id of processor FIRST */
	Softtlb*stb;			/* Software tlb simulation SECOND */
	Proc*	proc;			/* process on this processor THIRD */
	ulong	splpc;			/* pc that called splhi() FOURTH */
	int	tlbfault;		/* # of tlb faults FIFTH */
	int	tlbpurge;		/* MUST BE SIXTH */

	/* the following is safe to move */
	ulong	ticks;			/* of the clock since boot time */
	Label	sched;			/* scheduler wakeup */
	Lock	alarmlock;		/* access to alarm list */
	void*	alarm;			/* alarms bound to this clock */
	int	lastpid;		/* last pid allocated on this machine */
	Proc*	pidproc[NTLBPID];	/* proc that owns tlbpid on this mach */
	Page*	ufreeme;		/* address of upage of exited process */
	Ureg*	ur;
	KMap*	kactive;		/* active on this machine */
	int	knext;
	uchar	ktlbx[NTLB];		/* tlb index used for kmap */
	uchar	ktlbnext;
	int	speed;			/* cpu speed */
	ulong	delayloop;		/* for the delay() routine */

	int	pfault;
	int	cs;
	int	syscall;
	int	load;
	int	intr;
	int	ledval;			/* value last written to LED */

	int	stack[1];
};

struct KMap
{
	Ref;
	ulong	virt;
	ulong	phys0;
	ulong	phys1;
	KMap*	next;
	KMap*	konmach[MAXMACH];
	Page*	pg;
	char	inuse;			/* number of procs using kmap */
};

#define	VA(k)		((k)->virt)
#define PPN(x)		((x)>>6)

struct Softtlb
{
	ulong	virt;
	ulong	phys0;
	ulong	phys1;
};



struct
{
	Lock;
	short	machs;
	short	exiting;
}active;

extern KMap kpte[];
extern register Mach	*m;
extern register Proc	*up;

A carrera/devether.c => carrera/devether.c +462 -0
@@ 0,0 1,462 @@
#include	"u.h"
#include	"../port/lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"io.h"
#include	"../port/error.h"
#include	"../port/netif.h"

/*
 *  ethernet address stored in prom
 */
typedef struct
{
	ulong	pad0;
	ulong	byte;
	uvlong	pad1;
} Etheraddr;
#define	EPCENETPROM	EPCSWIN(Etheraddr, 0x2000)

/*
 *  SEEQ/EDLC device registers
 */
typedef struct
{
	struct
	{
	  ulong	pad;
	  ulong	byte;
	}	addr[6];	/* address */

	ulong	 pad;
	ulong	tcmd;		/* transmit command */
	ulong	 pad0;
	ulong	rcmd;		/* receive command */
	ulong	 pad1[5];
	ulong	tbaselo;	/* low bits of xmit buff base */
	ulong	 pad2;
	ulong	tbasehi;	/* high bits of xmit buff base */
	ulong	 pad3;
	ulong	tlimit;		/* xmit buffer limit */
	ulong	 pad4;
	ulong	tindex;		/* xmit buffer limit */
	ulong	 pad5;
	ulong	ttop;		/* xmit buffer top */
	ulong	 pad6;
	ulong	tbptr;		/* xmit buffer byte pointer */
	ulong	 pad7;
	ulong	tstat;		/* transmit status */
	ulong	 pad8;
	ulong	titimer;	/* transmit interrupt timer */
	ulong	 pad9[5];
	ulong	rbaselo;	/* rcv buffer base addr */
	ulong	 pad10;
	ulong	rbasehi;	/* high bits of rcv buffer base addr */
	ulong	 pad11;
	ulong	rlimit;		/* rcv buffer limit */
	ulong	 pad12;
	ulong	rindex;		/* rcv buffer index */
	ulong	 pad13;
	ulong	rtop;		/* rcv buffer top */
	ulong	 pad14;
	ulong	rbptr;		/* rcv buffer byte pointer */
	ulong	 pad15;
	ulong	rstat;		/* rcv status */
	ulong	 pad16;
	ulong	ritimer;	/* rcv interrupt timer */
} EDLCdev;
#define EPCEDLC	EPCSWIN(EDLCdev, 0xa200)

/*
 *  LXT901 device registers
 */
typedef struct {
	ulong	 pad0;
	ulong	stat;		/* some LXT901 pins + SQE ctrl (r/w) */
	ulong	 pad1;
	ulong	collisions;	/* total collisions -- 16 bits (r) */
	uchar	 pad2[7];
	uchar	loopback;	/* loopback enable -- 1 bit (w) */
	ulong	 pad3;
	ulong	edlcself;	/* EDLC self rcv enable -- 1 bit (w) */
} LXTdev;
#define EPCLXT	EPCSWIN(LXTdev, 0x8000)

enum
{
	/* transmit command bits */
	Tigood=		1<<3,		/* interrupt on good xmit */
	Ti16tries=	1<<2,		/* interrupt on 16 retries */
	Ticoll=		1<<1,		/* interrupt on collision */
	Tiunder=	1<<0,		/* interrupt on underflow */

	/* receive command bits */
	Rmulti=		3<<6,		/* recv station/broadcast/multicast */
	Rnormal=	2<<6,		/* recv station/broadcast */
	Rall=		1<<6,		/* receive all frames */
	Rigood=		1<<5,	 	/* interrupt on good frames */
	Riend=		1<<4,		/* interrupt on end of frame */
	Rishort=	1<<3,		/* interrupt on short frame */
	Ridrbl=		1<<2,		/* interrupt on dribble error */
	Ricrc=		1<<1,		/* interrupt on CRC error */
	Riover=		1<<0,		/* interrupt on overflow error */

	Renab=		(Rigood|Riend|Rishort|Ridrbl|Ricrc),

	/* receive status bits */
	Rgood=		1<<5,		/* good frame */
	Rend=		1<<4,		/* end of frame */
	Rshort=		1<<3,		/* short frame */
	Rdrbl=		1<<2,		/* dribble error */
	Rcrc=		1<<1,		/* CRC error */
	Rover=		1<<0,		/* overflow error */

	/* interrupt level for ether */
	ILenet=		0x60,

	/* manifest constants */
	logNxmt=	8,
	Nxmt=		1<<logNxmt,
	Tmask=		Nxmt-1,
	logNrcv=	8,
	Nrcv=		1<<logNrcv,
	Rmask=		Nrcv-1,
	Ntypes=		8,

	/* hold off values */
	ho800us=	0x100,	/* 800 us hold-off */
	ho1500us=	0x080,	/* 1500 us hold-off */
	ho2500us=	0x000,	/* 2500 us hold-off */
};

#define RSUCC(i)	(((i)+1)&Rmask)
#define RPREV(i)	(((i)-1)&Rmask)
#define TSUCC(i)	(((i)+1)&Tmask)
#define TPREV(i)	(((i)-1)&Tmask)

/*
 *  a hardware packet buffer
 */
typedef struct
{
	uchar	tlen[2];	/* transmit length */
	uchar	d[Eaddrlen];
	uchar	s[Eaddrlen];
	uchar	type[2];
	uchar	data[1500];
	uchar	pad1[2043-ETHERMAXTU];
	uchar	stat;
	uchar	rlen[2];	/* receive length */
} Pbuf;

struct Ether
{
	uchar	ea[6];

	int	rindex;		/* first rcv buffer owned by hardware */
	int	rtop;		/* first rcv buffer owned by software */
	int	tindex;		/* first rcv buffer owned by hardware */
	int	ttop;		/* first rcv buffer owned by software */

	Pbuf	*tbuf;		/* transmit buffers */
	Pbuf	*rbuf;		/* receive buffers */

	QLock	tlock;		/* lock for grabbing transmitter queue */
	Rendez	tr;		/* wait here for free xmit buffer */

	Netif;
} ether;


/*
 *  The dance in this code is very dangerous to change.  Do not
 *  change the order of any of the labeled steps.  This should run splhi.
 */
static void
etherhardreset(void)
{
	EDLCdev *edlc = EPCEDLC;
	LXTdev *lxt = EPCLXT;
	EPCmisc *misc = EPCMISC;
	ulong x, i;

	/* step 1: isolate from ether */
	lxt->loopback = 1;
	x = lxt->loopback; USED(x);

	/* step 2: shut off transmitter */
	while(edlc->ttop != edlc->tindex)
		edlc->ttop = edlc->tindex;
	ether.tindex = ether.ttop = edlc->ttop;

	/* step 3: reset edlc */
	misc->set = 0x200;
	x = misc->reset; USED(x);
	delay(1);	/* 1ms but 10micros is enough */
	misc->clr = 0x200;
	x = misc->reset; USED(x);

	/* step 4: enable transmitter interrupts */
	edlc->tcmd = Tigood | Ti16tries | Ticoll | Tiunder;

	/* step 5: set address from prom, start receiver,
	 * and reset receive pointer
	 */
	for(i = 0; i < Netheraddr; i++)
		edlc->addr[i].byte = EPCENETPROM[5-i].byte & 0xff;

	if(ether.prom)
		edlc->rcmd = Renab | Rall;
	else
		edlc->rcmd = Renab | Rnormal;

	ether.rindex = edlc->rindex;
	ether.rtop = edlc->rtop = RPREV(ether.rindex);

	/* step 6: attach to ether */
	lxt->loopback = 0;
}

void
etherintr(void)
{
	EDLCdev *edlc = EPCEDLC;
	EPCmisc *misc = EPCMISC;
	Netfile *f, **fp;
	Pbuf *p;
	int x;
	ushort t;

	while(edlc->rindex != ether.rindex){
		p = &ether.rbuf[ether.rindex];

		/* statistics */
		if(p->stat & (Rshort|Rdrbl|Rcrc|Rover)){
			if(p->stat & (Rdrbl|Rcrc))
				ether.crcs++;
			if(p->stat & Rover)
				ether.overflows++;
			if(p->stat & Rshort)
				ether.frames++;
		}
		if(p->stat & Rgood){
			x = (p->rlen[0]<<8) | p->rlen[1];
			t = (p->type[0]<<8) | p->type[1];
			for(fp = ether.f; fp < &ether.f[Ntypes]; fp++){
				f = *fp;
				if(f == 0)
					continue;
				if(f->type == t || f->type < 0)
					qproduce(f->in, p->d, x);
			}
		}

		/*
		 *  because of a chip bug, we have to reset if rtop
		 *  and rindex get too close.
		 */
		x = edlc->rtop - edlc->rindex;
		if(x < 0)
			x += Nrcv;
		if(x <= 64){
			etherhardreset();
		} else {
			edlc->rtop = ether.rindex;
			ether.rindex = RSUCC(ether.rindex);
		}
	}
	/* reenable holdoff and EPC interrupts */
	misc->clr = 0x10;
	misc->set = 0x10;
	epcenable(EIenet);
}

/*
 *  turn promiscuous mode on/off
 */
static void
promiscuous(void *arg, int on)
{
	EDLCdev *edlc = EPCEDLC;

	USED(arg);
	if(on)
		edlc->rcmd = Renab | Rall;
	else
		edlc->rcmd = Renab | Rnormal;
}

void
etherreset(void)
{
	EDLCdev *edlc = EPCEDLC;
	EPCmisc *misc = EPCMISC;
	ulong x, i;

	/* setup xmit buffers (pointers on chip assume KSEG0) */
	edlc->tlimit = logNxmt - 1;
	ether.tbuf = xspanalloc(Nxmt*sizeof(Pbuf), 512*1024, 0);
	x = ((ulong)ether.tbuf) & ~KSEGM;
	edlc->tbasehi = 0;
	edlc->tbaselo = x;

	/* setup rcv buffers (pointers on chip assume KSEG0) */
	edlc->rlimit = logNrcv - 1;
	ether.rbuf = xspanalloc(Nrcv*sizeof(Pbuf), 512*1024, 0);
	x = ((ulong)ether.rbuf) & ~KSEGM;
	edlc->rbasehi = 0;
	edlc->rbaselo = x;

	/* install interrupt handler */
	sethandler(ILenet, etherintr);
	setleveldest(ILenet, 0, &EPCINTR->enetdest);
	epcenable(EIenet);

	/* turn off receive */
	edlc->rcmd = 0;

	/* stop transmitter, we can't change tindex so we change ttop */
	while(edlc->ttop != edlc->tindex)
		edlc->ttop = edlc->tindex;
	ether.tindex = ether.ttop = edlc->ttop;

	/* enable transmitter interrupts */
	edlc->tcmd = Tigood | Ti16tries | Ticoll | Tiunder;

	/* set address from prom, start receiver, and reset receive pointer */
	for(i = 0; i < Netheraddr; i++){
		ether.ea[i] = EPCENETPROM[5-i].byte & 0xff;
		edlc->addr[i].byte = ether.ea[i];
	}
	ether.rindex = edlc->rindex;
	ether.rtop = edlc->rtop = RPREV(ether.rindex);

	edlc->rcmd = Renab | Rnormal;

	/* set hold off timer value, and enable its interrupts (pulse) */
	misc->set = ho800us;
	misc->clr = (~ho800us)&0x180;
	misc->clr = 0x10;
	misc->set = 0x10;

	/* general network interface structure */
	netifinit(&ether, "ether", Ntypes, 32*1024);
	ether.alen = 6;
	memmove(ether.addr, ether.ea, 6);
	memmove(ether.bcast, etherbcast, 6);
	ether.promiscuous = promiscuous;
	ether.arg = &ether;
}

void
etherinit(void)
{
}

Chan*
etherattach(char *spec)
{
	return devattach('l', spec);
}

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

int
etherwalk(Chan *c, char *name)
{
	return netifwalk(&ether, c, name);
}

Chan*
etheropen(Chan *c, int omode)
{
	return netifopen(&ether, c, omode);
}

void
ethercreate(Chan *c, char *name, int omode, ulong perm)
{
	USED(c, name, omode, perm);
}

void
etherclose(Chan *c)
{
	netifclose(&ether, c);
}

long
etherread(Chan *c, void *buf, long n, ulong offset)
{
	return netifread(&ether, c, buf, n, offset);
}

static int
isoutbuf(void *arg)
{
	EDLCdev *edlc = arg;

	USED(arg);
	ether.tindex = edlc->tindex;
	return TSUCC(ether.ttop) != ether.tindex;
}

long
etherwrite(Chan *c, void *buf, long n, ulong offset)
{
	Pbuf *p;
	EDLCdev *edlc = EPCEDLC;

	USED(offset);

	if(n > ETHERMAXTU)
		error(Ebadarg);

	/* etherif.c handles structure */
	if(NETTYPE(c->qid.path) != Ndataqid)
		return netifwrite(&ether, c, buf, n);

	/* we handle data */
	qlock(&ether.tlock);
	tsleep(&ether.tr, isoutbuf, edlc, 10000);
	if(!isoutbuf(edlc)){
		print("ether transmitter jammed\n");
	} else {
		p = &ether.tbuf[ether.ttop];
		memmove(p->d, buf, n);
		if(n < 60) {
			memset(p->d+n, 0, 60-n);
			n = 60;
		}
		memmove(p->s, ether.ea, sizeof(ether.ea));
		p->tlen[0] = n;
		p->tlen[1] = n>>8;
		ether.ttop = TSUCC(ether.ttop);
		edlc->ttop = ether.ttop;
	}
	qunlock(&ether.tlock);
	return n;
}

void
etherremove(Chan *c)
{
	USED(c);
}

void
etherstat(Chan *c, char *dp)
{
	netifstat(&ether, c, dp);
}

void
etherwstat(Chan *c, char *dp)
{
	netifwstat(&ether, c, dp);
}

A carrera/faultmips.c => carrera/faultmips.c +160 -0
@@ 0,0 1,160 @@
#include	"u.h"
#include	"../port/lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"ureg.h"
#include	"../port/error.h"
#include	"io.h"

/*
 * Ask if the instruction at EPC could have cause this badvaddr
 */
int
tstbadvaddr(Ureg *ur, int read)
{
	int rn;
	ulong iw, off, ea;

	if(ur->cause & (1<<31))
		iw = ur->pc+4;
	else
		iw = ur->pc;

	if(seg(up, iw, 0) == 0)
		return 0;

	iw = *(ulong*)iw;

/*	print("iw: %lux\n", iw);	/**/

	switch((iw>>26) & 0x3f) {
	default:
		return 1;
	case 0x20:	/* LB */
	case 0x24:	/* LBU */
			/* LD */
	case 0x35:
	case 0x36:
	case 0x37:	/* LDCz */
	case 0x1A:	/* LDL */
	case 0x1B:	/* LDR */
	case 0x21:	/* LH */
	case 0x25:	/* LHU */
	case 0x30:	/* LL */
	case 0x34:	/* LLD */
	case 0x23:	/* LW */
	case 0x31:
	case 0x32:	/* LWCz possible 0x33 */
	case 0x27:	/* LWU */
	case 0x22:	/* LWL */
	case 0x26:	/* LWR */
		if(!read)
			print("bogus: load causes store fault\n");
		break;

	case 0x28:	/* SB */
	case 0x38:	/* SC */
	case 0x3C:	/* SCD */
	case 0x3D:
	case 0x3E:
	case 0x3F:	/* SDCz */
	case 0x2C:	/* SDL */
	case 0x2D:	/* SDR */
	case 0x29:	/* SH */
	case 0x2B:	/* SW */
	case 0x39:
	case 0x3A:	/* SWCz */
	case 0x2A:	/* SWL */
	case 0x2E:	/* SWR */
		if(read)
			print("bogus: store causes load fault\n");
		break;
	}

	off = iw & 0xffff;
	if(off & 0x8000)
		off |= ~0xffff;

	rn = (iw>>21) & 0x1f;
	switch(rn) {
	case 0:
		ea = off;
		break;
	case 31:
		ea = ur->r31 + off;
		break;
	case 30:
		ea = ur->r30 + off;
		break;
	case 29:
		ea = ur->sp + off;
		break;
	default:
		/* depends horribly on ureg.h */
		ea = ((ulong*)&ur->r1)[1-rn];
		ea += off;
		break;
	}

	/* print("ea %lux 0x%lux(R%d) bv 0x%lux pc 0x%lux\n", ea, off, rn, ur->badvaddr, ur->pc); /**/

	if(ur->badvaddr == ea)
		return 0;

	return 1;
}

/*
 *  find out fault address and type of access.
 *  Call common fault handler.
 */
void
faultmips(Ureg *ur, int user, int code)
{
	int read;
	ulong addr;
	extern char *excname[];
	char *p, buf[ERRLEN];

	addr = ur->badvaddr;

	addr &= ~(BY2PG-1);
	read = !(code==CTLBM || code==CTLBS);

/*	print("fault: %s code %d va %lux pc %lux r31 %lux %lux\n", up->text, code, ur->badvaddr, ur->pc, ur->r31, tlbvirt());/**/

	if(fault(addr, read) == 0)
		return;

	if(tstbadvaddr(ur, read)) {
/*		print("spurious badvaddr 0x%lux in %s at pc 0x%lux\n", ur->badvaddr, up->text, ur->pc);/**/
		return;
	}

	if(user) {
		p = "store";
		if(read)
			p = "load";
		sprint(buf, "sys: trap: fault %s addr=0x%lux r31=0x%lux", p, ur->badvaddr, ur->r31);
		postnote(up, 1, buf, NDebug);
		return;
	}

	print("kernel %s vaddr=0x%lux\n", excname[code], ur->badvaddr);
	print("st=0x%lux pc=0x%lux sp=0x%lux\n", ur->status, ur->pc, ur->sp);
	dumpregs(ur);
	panic("fault");
}

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

A carrera/fns.h => carrera/fns.h +115 -0
@@ 0,0 1,115 @@
#include "../port/portfns.h"

void	DEBUG(void);

void	addportintr(int(*)(void));
void	allflush(void*, ulong);
void	audiointr(void);
void	arginit(void);
int	busprobe(ulong);
void	cleancache(void);
void	clearmmucache(void);
void	clockinit(void);
ulong	confeval(char*);
void	confprint(void);
void	confread(void);
void	confset(char*);
int	conschar(void);
void	consoff(void);
int	consputc(int);
void	dcflush(void*, ulong);
void	dcinvalidate(void*, ulong);
void	devportintr(void);
void	epcenable(ulong);
void	epcinit(int, int);
void	evenaddr(ulong);
void	faultmips(Ureg*, int, int);
ulong	fcr31(void);
void	firmware(int);
#define	flushpage(s)	icflush((void*)(s), BY2PG)
void	fptrap(Ureg*);
ulong	getcallerpc(void*);
int	getline(char*, int);
void	getnveaddr(void*);
int	getnvram(ulong, void *, int);
ulong	getstatus(void);
void	gettlb(int, ulong*);
int	gettlbp(ulong, ulong*);
ulong	gettlbvirt(int);
void	gotopc(ulong);
void	hinv(void);
void	icdirty(void *, ulong);
void	icflush(void *, ulong);
void	intr(Ureg*);
void	ioinit(void);
int	iprint(char*, ...);
int	kbdinit(void);
int	kbdintr(void);
void	kfault(ulong);
KMap*	kmap(Page*);
void	kmapinit(void);
void	kmapinval(void);
int	kprint(char*, ...);
void	kproftimer(ulong);
void	kunmap(KMap*);
void	launchinit(void);
void	launch(int);
void	lightbits(int, int);
void	lptintr(void);
ulong	machstatus(void);
void	mmunewpage(Page*);
void	mntdump(void);
void	newstart(void);
int	newtlbpid(Proc*);
void	nonettoggle(void);
void	novme(int);
void	online(void);
Block*	prepend(Block*, int);
void	prflush(void);
ulong	prid(void);
void	printinit(void);
#define	procrestore(p)
#define	procsave(p)
#define	procsetup(p)	((p)->fpstate = FPinit)
void	purgetlb(int);
int	putnvram(ulong, void*, int);
Softtlb*	putstlb(ulong, ulong);
int	puttlb(ulong, ulong, ulong);
void	puttlbx(int, ulong, ulong, ulong, int);
void*	pxalloc(ulong);
void*	pxspanalloc(ulong, int, ulong);
ulong	rdcount(void);
int	readlog(ulong, char*, ulong);
void	restfpregs(FPsave*, ulong);
void	screeninit(int);
#define	screenputs 
void	sethandler(int, void(*)(void));
void	setled(int);
void	setleveldest(int, int, uvlong*);
void	sinit(void);
uchar*	smap(int, uchar*);
void	sunmap(int, uchar*);
void	syslog(char*, int);
void	sysloginit(void);
int	tas(ulong*);
void	tlbinit(void);
ulong	tlbvirt(void);
void	touser(void*);
ulong	uvmove(uvlong*, uvlong*);
void	vecinit(void);
void	vector0(void);
void	vector100(void);
void	vector180(void);
void	vmereset(void);
void	wbflush(void);
void	wrcompare(ulong);
void	Xdelay(int);

void	NS16552special(int, int, Queue**, Queue**, int (*)(Queue*, int));
void	NS16552setup(ulong, ulong);

#define	waserror()	setlabel(&up->errlab[up->nerrlab++])
#define	kmapperm(x)	kmap(x)
#define KADDR(a)	((void*)((ulong)(a)|KSEG0))
#define KADDR1(a)	((void*)((ulong)(a)|KSEG1))
#define PADDR(a)	((ulong)(a)&~KSEGM)

A carrera/fptrap.c => carrera/fptrap.c +283 -0
@@ 0,0 1,283 @@
#include	"u.h"
#include	"../port/lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"ureg.h"
#include	"io.h"
#include	"../port/error.h"

enum	/* op */
{
	ABS =	5,
	ADD =	0,
	CVTD = 	33,
	CVTS =	32,
	CVTW =	36,
	DIV =	3,
	MOV =	6,
	MUL =	2,
	NEG =	7,
	SUB =	1,
};

static int	fpunimp(ulong);
static ulong	branch(Ureg*, ulong);

void
fptrap(Ureg *ur)
{
	ulong iw, npc;

	if((up->fpsave.fpstatus&(1<<17)) == 0)
		return;

print("fpt: %d %s %lux\n", up->pid, up->text, up->fpsave.fpstatus);

	if(ur->cause & (1<<31))
		iw = *(ulong*)(ur->pc+4);
	else
		iw = *(ulong*)ur->pc;

	if(fpunimp(iw) == 0)
		return;

	if(ur->cause & (1<<31)){
		npc = branch(ur, up->fpsave.fpstatus);
		if(npc == 0)
			return;
		ur->pc = npc;
	}
	else
		ur->pc += 4;

	up->fpsave.fpstatus = up->fpsave.fpstatus & ~(1<<17);
}

static void
unpack(FPsave *f, int fmt, int reg, int *sign, int *exp)
{
	*sign = 1;
	if(f->fpreg[reg] & 0x80000000)
		*sign = -1;

	switch(fmt){
	case 0:
		*exp = ((f->fpreg[reg]>>23)&0xFF) - ((1<<7)-2);
		break;
	case 1:
		if(reg & 1)	/* shouldn't happen */
			reg &= ~1;
		*exp = ((f->fpreg[reg]>>20)&0x7FF) - ((1<<10)-2);
		break;
	}
}

static void
zeroreg(FPsave *f, int fmt, int reg, int sign)
{
	int size;

	size = 0;
	switch(fmt){
	case 0:
		size = 4;
		break;
	case 1:
		if(reg & 1)
			reg &= ~1;
		size = 8;
		break;
	}
	memset(&f->fpreg[reg], 0, size);
	if(sign < 0)
		f->fpreg[reg] |= 0x80000000;
}

static int
fpunimp(ulong iw)
{
	int ss, st, sd;
	int es, et, ed;
	int maxe, maxm;
	ulong op, fmt, ft, fs, fd;

	if((iw>>25) != 0x23)
		return 0;
	op = iw & ((1<<6)-1);
	fmt = (iw>>21) & ((1<<4)-1);
	ft = (iw>>16) & ((1<<5)-1);
	fs = (iw>>11) & ((1<<5)-1);
	fd = (iw>>6) & ((1<<5)-1);
	unpack(&up->fpsave, fmt, fs, &ss, &es);
	unpack(&up->fpsave, fmt, ft, &st, &et);
	ed = 0;
	maxe = 0;
	maxm = 0;
	switch(fmt){
	case 0:
		maxe = 1<<7;
		maxm = 24;
		break;
	case 1:
		maxe = 1<<10;
		maxm = 53;
		break;
	}
	switch(op){
	case ABS:
		up->fpsave.fpreg[fd] &= ~0x80000000;
		return 1;

	case NEG:
		up->fpsave.fpreg[fd] ^= 0x80000000;
		return 1;

	case SUB:
		st = -st;
	case ADD:
		if(es<-(maxe-maxm) && et<-(maxe-maxm))
			ed = -maxe;
		if(es > et)
			sd = es;
		else
			sd = et;
		break;

	case DIV:
		et = -et;
	case MUL:
		sd = 1;
		if(ss != st)
			sd = -1;
		ed = es + et;
		break;

	case CVTS:
		if(fmt != 1)
			return 0;
		fmt = 0;	/* convert FROM double TO single */
		maxe = 1<<7;
		ed = es;
		sd = ss;
		break;

	default:	/* probably a compare */
		return 0;
	}
	if(ed <= -(maxe-4)){	/* guess: underflow */
		zeroreg(&up->fpsave, fmt, fd, sd);
		/* Set underflow exception and sticky */
		up->fpsave.fpstatus |= (1<<3)|(1<<13);
		return 1;
	}
	return 0;
}

static ulong*
reg(Ureg *ur, int regno)
{
	/* regs go from R31 down in ureg, R29 is missing */
	if(regno == 31)
		return &ur->r31;
	if(regno == 30)
		return &ur->r30;
	if(regno == 29)
		return &ur->sp;
	return (&ur->r28) + (28-regno);
}

static ulong
branch(Ureg *ur, ulong fcr31)
{
	ulong iw, npc, rs, rt, rd, offset;

	iw = *(ulong*)ur->pc;
	rs = (iw>>21) & 0x1F;
	if(rs)
		rs = *reg(ur, rs);
	rt = (iw>>16) & 0x1F;
	if(rt)
		rt = *reg(ur, rt);
	offset = iw & ((1<<16)-1);
	if(offset & (1<<15))	/* sign extend */
		offset |= ~((1<<16)-1);
	offset <<= 2;
	/*
	 * Integer unit jumps first
	 */
	switch(iw>>26){
	case 0:			/* SPECIAL: JR or JALR */
		switch(iw&0x3F){
		case 0x09:	/* JALR */
			rd = (iw>>11) & 0x1F;
			if(rd)
				*reg(ur, rd) = ur->pc+8;
			/* fall through */
		case 0x08:	/* JR */
			return rs;
		default:
			return 0;
		}
	case 1:			/* BCOND */
		switch((iw>>16) & 0x1F){
		case 0x10:	/* BLTZAL */
			ur->r31 = ur->pc + 8;
			/* fall through */
		case 0x00:	/* BLTZ */
			if((long)rs < 0)
				return ur->pc+4 + offset;
			return ur->pc + 8;
		case 0x11:	/* BGEZAL */
			ur->r31 = ur->pc + 8;
			/* fall through */
		case 0x01:	/* BGEZ */
			if((long)rs >= 0)
				return ur->pc+4 + offset;
			return ur->pc + 8;
		default:
			return 0;
		}
	case 3:			/* JAL */
		ur->r31 = ur->pc+8;
		/* fall through */
	case 2:			/* JMP */
		npc = iw & ((1<<26)-1);
		npc <<= 2;
		return npc | (ur->pc&0xF0000000);
	case 4:			/* BEQ */
		if(rs == rt)
			return ur->pc+4 + offset;
		return ur->pc + 8;
	case 5:			/* BNE */
		if(rs != rt)
			return ur->pc+4 + offset;
		return ur->pc + 8;
	case 6:			/* BLEZ */
		if((long)rs <= 0)
			return ur->pc+4 + offset;
		return ur->pc + 8;
	case 7:			/* BGTZ */
		if((long)rs > 0)
			return ur->pc+4 + offset;
		return ur->pc + 8;
	}
	/*
	 * Floating point unit jumps
	 */
	if((iw>>26) == 0x11)	/* COP1 */
		switch((iw>>16) & 0x3C1){
		case 0x101:	/* BCT */
		case 0x181:	/* BCT */
			if(fcr31 & (1<<23))
				return ur->pc+4 + offset;
			return ur->pc + 8;
		case 0x100:	/* BCF */
		case 0x180:	/* BCF */
			if(!(fcr31 & (1<<23)))
				return ur->pc+4 + offset;
			return ur->pc + 8;
		}
	/* shouldn't get here */
	return 0;
}

A carrera/io.h => carrera/io.h +28 -0
@@ 0,0 1,28 @@
enum
{
	Devicephys	= 0x80000000,
	Devicevirt	= 0xE0000000,
	Dmabase		= 0xE0000000,	
	Sonicbase	= 0xE0001000,    	
	Scsibase 	= 0xE0002000,   	
	Floppybase	= 0xE0003000,	
	Clockbase	= 0xE0004000,	
	Uart0		= 0xE0006000,	
	Uart1		= 0xE0007000,	
	  UartFREQ	= 4233600,
	Centronics	= 0xE0008000,
	Nvram		= 0xE0009000, 	
	NvramRW		= 0xE000A000,
	NvramRO		= 0xE000B000,
	KeyboardIO	= 0xE0005000,	
	MouseIO		= 0xE0005000,  	
	SoundIO		= 0xE000C000,
	EisaLatch	= 0xE000E000,
	Diag		= 0xE000F000,
	VideoCTL	= 0x60000000,	
	VideoMEM	= 0x40000000, 	
	EisaIO		= 0xE2000000,	
	EisaMEM		= 0xE3000000,
	PromMEM		= 0xE1000000,   	
	Intctl		= 0xE0100000,
};

A carrera/l.s => carrera/l.s +863 -0
@@ 0,0 1,863 @@
#include "mem.h"

#define SP		R29

#define PROM		(KSEG1+0x1C000000)
#define	NOOP		WORD	$0x27
#define FCRNOOP		NOOP; NOOP; NOOP
#define	WAIT		NOOP; NOOP
#define	NOOP4		NOOP; NOOP; NOOP; NOOP

#define	ERET		NOOP4;NOOP4;WORD	$0x42000018;NOOP4;NOOP4

#define	CONST(x,r)	MOVW $((x)&0xffff0000), r; OR  $((x)&0xffff), r

/*
 *  R4000 instructions
 */
#define	LD(base, rt)		WORD	$((067<<26)|((base)<<21)|((rt)<<16))
#define STD(rt, base)		WORD	$((077<<26)|((base)<<21)|((rt)<<16))
#define	DSLL(sa, rt, rd)	WORD	$(((rt)<<16)|((rd)<<11)|((sa)<<6)|070)
#define	DSRA(sa, rt, rd)	WORD	$(((rt)<<16)|((rd)<<11)|((sa)<<6)|073)
#define	LL(base, rt)		WORD	$((060<<26)|((base)<<21)|((rt)<<16))
#define	SC(base, rt)		WORD	$((070<<26)|((base)<<21)|((rt)<<16))

/*
 * Boot first processor
 */
TEXT	start(SB), $-4

	MOVW	$setR30(SB), R30
	MOVW	$(CU1|INTR7|INTR6|INTR5|INTR4|INTR3|INTR2|INTR1|INTR0), R1
	MOVW	R1, M(STATUS)
	WAIT

	MOVW	$TLBROFF, R1
	MOVW	R1, M(WIRED)

	MOVW	$((0x1C<<7)|(1<<24)), R1
	MOVW	R1, FCR31	/* permit only inexact and underflow */
	NOOP
	MOVD	$0.5, F26
	SUBD	F26, F26, F24
	ADDD	F26, F26, F28
	ADDD	F28, F28, F30

	MOVD	F24, F0
	MOVD	F24, F2
	MOVD	F24, F4
	MOVD	F24, F6
	MOVD	F24, F8
	MOVD	F24, F10
	MOVD	F24, F12
	MOVD	F24, F14
	MOVD	F24, F16
	MOVD	F24, F18
	MOVD	F24, F20
	MOVD	F24, F22

	MOVW	$MACHADDR, R(MACH)
	ADDU	$(BY2PG-4), R(MACH), SP
	MOVW	$0, R(USER)
	MOVW	R0, 0(R(MACH))

	MOVW	$edata(SB), R1
	MOVW	$end(SB), R2

clrbss:
	MOVB	$0, (R1)
	ADDU	$1, R1
	BNE	R1, R2, clrbss

	MOVW	R4, _argc(SB)
	MOVW	R5, _argv(SB)
	MOVW	R6, _env(SB)
	JAL	main(SB)
	JMP	(R0)

/*
 * Take first processor into user mode
 * 	- argument is stack pointer to user
 */

TEXT	touser(SB), $-4

	MOVW	$(UTZERO+32), R2	/* header appears in text */
	MOVW	(R2), R3		/* fault now */
	MOVW	M(STATUS), R4
	WAIT
	AND	$(~KMODEMASK), R4
	OR	$(KUSER|EXL|IE), R4
	MOVW	R4, M(STATUS)
	WAIT
	MOVW	R1, SP
	MOVW	R2, M(EPC)
	NOOP4
	ERET

TEXT	firmware(SB), $0

	SLL	$3, R1
	MOVW	$(PROM+0x774), R1
	JMP	(R1)

TEXT	splhi(SB), $0

	MOVW	R31, 12(R(MACH))	/* save PC in m->splpc */
	MOVW	M(STATUS), R1
	WAIT
	AND	$~IE, R1, R2
	MOVW	R2, M(STATUS)
	WAIT
	RET

TEXT	splx(SB), $0

	MOVW	R31, 12(R(MACH))	/* save PC in m->splpc */
	MOVW	M(STATUS), R2
	WAIT
	AND	$IE, R1
	AND	$~IE, R2
	OR	R2, R1
	MOVW	R1, M(STATUS)
	WAIT
	RET

TEXT	spllo(SB), $0

	MOVW	M(STATUS), R1
	WAIT
	OR	$IE, R1, R2
	MOVW	R2, M(STATUS)
	WAIT
	RET

TEXT	machstatus(SB), $0

	MOVW	M(STATUS), R1
	WAIT
	RET

TEXT	spldone(SB), $0

	RET

TEXT	wbflush(SB), $-4

	RET

TEXT	setlabel(SB), $-4

	MOVW	R29, 0(R1)
	MOVW	R31, 4(R1)
	MOVW	$0, R1
	RET

TEXT	gotolabel(SB), $-4

	MOVW	0(R1), R29
	MOVW	4(R1), R31
	MOVW	$1, R1
	RET

TEXT	gotopc(SB), $8

	MOVW	R1, 0(FP)		/* save arguments for later */
	MOVW	$(64*1024), R7
	MOVW	R7, 8(SP)
	JAL	icflush(SB)
	MOVW	0(FP), R7
	MOVW	_argc(SB), R4
	MOVW	_argv(SB), R5
	MOVW	_env(SB), R6
	MOVW	R0, 4(SP)
	JMP	(R7)

TEXT	puttlb(SB), $0

	MOVW	R1, M(TLBVIRT)
	MOVW	4(FP), R2		/* phys0 */
	MOVW	8(FP), R3		/* phys1 */
	MOVW	R2, M(TLBPHYS0)
	WAIT
	MOVW	$PGSZ4K, R1
	MOVW	R3, M(TLBPHYS1)
	WAIT
	MOVW	R1, M(PAGEMASK)
	OR	R2, R3, R4		/* MTC0 delay slot */
	AND	$PTEVALID, R4		/* MTC0 delay slot */
	NOOP
	TLBP
	NOOP4
	MOVW	M(INDEX), R1
	NOOP4
	BGEZ	R1, index
	BEQ	R4, dont		/* cf. kunmap */
	TLBWR
	NOOP
dont:
	RET
index:
	TLBWI
	NOOP
	RET

TEXT	getwired(SB),$0
	MOVW	M(WIRED), R1
	WAIT
	RET

TEXT	getrandom(SB),$0
	MOVW	M(RANDOM), R1
	WAIT
	RET

TEXT	puttlbx(SB), $0

	MOVW	4(FP), R2
	MOVW	8(FP), R3
	MOVW	12(FP), R4
	MOVW	16(FP), R5
	MOVW	R2, M(TLBVIRT)
	NOOP4
	MOVW	R3, M(TLBPHYS0)
	NOOP4
	MOVW	R4, M(TLBPHYS1)
	NOOP4
	MOVW	R5, M(PAGEMASK)
	NOOP4
	MOVW	R1, M(INDEX)
	NOOP4
	TLBWI
	WAIT
	RET

TEXT	tlbvirt(SB), $0

	NOOP
	MOVW	M(TLBVIRT), R1
	NOOP
	RET

TEXT	gettlbx(SB), $0

	MOVW	4(FP), R5
	MOVW	M(TLBVIRT), R10
	NOOP4
	MOVW	R1, M(INDEX)
	NOOP4
	TLBR
	NOOP4
	MOVW	M(TLBVIRT), R2
	MOVW	M(TLBPHYS0), R3
	MOVW	M(TLBPHYS1), R4
	NOOP4
	MOVW	R2, 0(R5)
	MOVW	R3, 4(R5)
	MOVW	R4, 8(R5)
	MOVW	R10, M(TLBVIRT)
	NOOP4
	RET

TEXT	gettlbp(SB), $0

	MOVW	4(FP), R5
	MOVW	R1, M(TLBVIRT)
	NOOP
	NOOP
	NOOP
	TLBP
	NOOP
	NOOP
	MOVW	M(INDEX), R1
	NOOP
	BLTZ	R1, gettlbp1
	TLBR
	NOOP
	NOOP
	NOOP
	MOVW	M(TLBVIRT), R2
	MOVW	M(TLBPHYS0), R3
	MOVW	M(TLBPHYS1), R4
	MOVW	M(PAGEMASK), R6
	NOOP
	MOVW	R2, 0(R5)
	MOVW	R3, 4(R5)
	MOVW	R4, 8(R5)
	MOVW	R6, 12(R5)
gettlbp1:
	RET

TEXT	gettlbvirt(SB), $0

	MOVW	R1, M(INDEX)
	NOOP
	NOOP
	TLBR
	NOOP
	NOOP
	NOOP
	MOVW	M(TLBVIRT), R1
	NOOP
	RET

TEXT	vector0(SB), $-4

	NOOP4
	NOOP4
	MOVW	$utlbmiss(SB), R26
	JMP	(R26)

TEXT	utlbmiss(SB), $-4

	MOVW	M(TLBVIRT), R27
	WAIT
	MOVW	R27, R26
	SRL	$13, R27
	XOR	R26, R27
	AND	$(STLBSIZE-1), R27
	SLL	$2, R27
	MOVW	R27, R26
	SLL	$1, R27
	ADDU	R26, R27
	/* R27 = ((tlbvirt^(tlbvirt>>13)) & (STLBSIZE-1)) x 12 */

	CONST	(MACHADDR, R26)		/* R26 = m-> */
	MOVW	4(R26), R26		/* R26 = m->stb */
	ADDU	R26, R27		/* R27 = &m->stb[hash] */

	MOVW	M(BADVADDR), R26
	WAIT
	AND	$BY2PG, R26
	BNE	R26, utlbodd

	MOVW	4(R27), R26
	BEQ	R26, stlbm
	MOVW	R26, M(TLBPHYS0)
	WAIT
	MOVW	8(R27), R26
	MOVW	R26, M(TLBPHYS1)
	JMP	utlbcom

utlbodd:
	MOVW	8(R27), R26
	BEQ	R26, stlbm
	MOVW	R26, M(TLBPHYS1)
	WAIT
	MOVW	4(R27), R26
	MOVW	R26, M(TLBPHYS0)

utlbcom:
	WAIT				/* MTC0/MFC0 hazard */
	MOVW	M(TLBVIRT), R26
	WAIT
	MOVW	(R27), R27
	BEQ	R27, stlbm
	BNE	R26, R27, stlbm 

	MOVW	$PGSZ4K, R27
	MOVW	R27, M(PAGEMASK)
	NOOP4
	TLBP
	NOOP4
	MOVW	M(INDEX), R26
	NOOP4
	BGEZ	R26, utlindex
	TLBWR
	NOOP4
	ERET
utlindex:
	MOVW	R0,(R0)
	TLBWI
	NOOP4
	ERET

stlbm:
	MOVW	$exception(SB), R26
	JMP	(R26)

TEXT	vector100(SB), $-4

	NOOP4
	NOOP4
	MOVW	$exception(SB), R26
	JMP	(R26)

TEXT	vector180(SB), $-4

	NOOP4
	NOOP4
	MOVW	$exception(SB), R26
	JMP	(R26)
	NOP

TEXT	exception(SB), $-4
	MOVW	M(STATUS), R26
	WAIT
	AND	$KUSER, R26
	BEQ	R26, waskernel

wasuser:
	CONST	(MACHADDR, R27)		/* R27 = m-> */
	MOVW	8(R27), R26		/* R26 = m->proc */
	MOVW	8(R26), R27		/* R27 = m->proc->kstack */
	MOVW	SP, R26			/* save user sp */
	ADDU	$(KSTACK-UREGSIZE-2*BY2WD), R27, SP

	MOVW	R26, 0x10(SP)			/* user SP */
	MOVW	R31, 0x28(SP)
	MOVW	R30, 0x2C(SP)
	MOVW	M(CAUSE), R26
	MOVW	R(MACH), 0x3C(SP)
	MOVW	R(USER), 0x40(SP)
	AND	$(EXCMASK<<2), R26
	SUBU	$(CSYS<<2), R26

	JAL	saveregs(SB)

	MOVW	$setR30(SB), R30
	CONST	(MACHADDR, R1)
	ADDU	R1, R(MACH)			/* R(MACH) = m-> */
	MOVW	8(R(MACH)), R(USER)		/* up = m->proc */
	MOVW	4(SP), R1			/* first arg for syscall/trap */
	BNE	R26, notsys

	JAL	syscall(SB)
	MOVW	R0, R2
	MOVW	R0, R3
	MOVW	R0, R4
	MOVW	R0, R5
	MOVW	R0, R6
	MOVW	R0, R7
	MOVW	R0, R8
	MOVW	R0, R9
	MOVW	R0, R10
	MOVW	R0, R11
	MOVW	R0, R12
	MOVW	R0, R13
	MOVW	R0, R14
	MOVW	R0, R15
	MOVW	R0, R16
	MOVW	R0, R17
	MOVW	R0, R18
	MOVW	R0, R19
	MOVW	R0, R20
	MOVW	R0, R21
	MOVW	R0, R22
	MOVW	R0, R23
	MOVW	R0, R24
	MOVW	R0, R25
	MOVW	R0, R27

sysrestore:
	MOVW	0x28(SP), R31
	MOVW	0x08(SP), R26
	MOVW	0x2C(SP), R30
	MOVW	R26, M(STATUS)
	WAIT
	MOVW	0x0C(SP), R26		/* old pc */
	MOVW	0x10(SP), SP
	MOVW	R26, M(EPC)
	NOOP4
	ERET

notsys:
	JAL	trap(SB)

restore:
	JAL	restregs(SB)
	MOVW	0x28(SP), R31
	MOVW	0x2C(SP), R30
	MOVW	0x3C(SP), R(MACH)
	MOVW	0x40(SP), R(USER)
	MOVW	0x10(SP), SP
	MOVW	R26, M(EPC)
	NOOP4
	ERET

waskernel:
	MOVW	$1, R26			/* not syscall */
	MOVW	SP, -(UREGSIZE-16)(SP)
	SUBU	$UREGSIZE, SP
	MOVW	R31, 0x28(SP)
	JAL	saveregs(SB)
	MOVW	4(SP), R1		/* first arg for trap */
	JAL	trap(SB)
	JAL	restregs(SB)
	MOVW	0x28(SP), R31
	ADDU	$UREGSIZE, SP
	MOVW	R26, M(EPC)
	NOOP4
	ERET

TEXT	forkret(SB), $0
	MOVW	R0, R1			/* Fake out system call return */
	JMP	sysrestore

TEXT	saveregs(SB), $-4
	MOVW	R1, 0x9C(SP)
	MOVW	R2, 0x98(SP)
	ADDU	$8, SP, R1
	MOVW	R1, 0x04(SP)		/* arg to base of regs */
	MOVW	M(STATUS), R1
	MOVW	M(EPC), R2
	WAIT
	MOVW	R1, 0x08(SP)
	MOVW	R2, 0x0C(SP)

	MOVW	$(~KMODEMASK),R2	/* don't let him use R28 */
	AND	R2, R1
	MOVW	R1, M(STATUS)
	WAIT
	BEQ	R26, return		/* sys call, don't save */

	MOVW	M(CAUSE), R1
	MOVW	M(BADVADDR), R2
	NOOP
	MOVW	R1, 0x14(SP)
	MOVW	M(TLBVIRT), R1
	NOOP
	MOVW	R2, 0x18(SP)
	MOVW	R1, 0x1C(SP)
	MOVW	HI, R1
	MOVW	LO, R2
	MOVW	R1, 0x20(SP)
	MOVW	R2, 0x24(SP)
					/* LINK,SB,SP missing */
	MOVW	R28, 0x30(SP)
					/* R27, R26 not saved */
					/* R25, R24 missing */
	MOVW	R23, 0x44(SP)
	MOVW	R22, 0x48(SP)
	MOVW	R21, 0x4C(SP)
	MOVW	R20, 0x50(SP)
	MOVW	R19, 0x54(SP)
	MOVW	R18, 0x58(SP)
	MOVW	R17, 0x5C(SP)
	MOVW	R16, 0x60(SP)
	MOVW	R15, 0x64(SP)
	MOVW	R14, 0x68(SP)
	MOVW	R13, 0x6C(SP)
	MOVW	R12, 0x70(SP)
	MOVW	R11, 0x74(SP)
	MOVW	R10, 0x78(SP)
	MOVW	R9, 0x7C(SP)
	MOVW	R8, 0x80(SP)
	MOVW	R7, 0x84(SP)
	MOVW	R6, 0x88(SP)
	MOVW	R5, 0x8C(SP)
	MOVW	R4, 0x90(SP)
	MOVW	R3, 0x94(SP)
return:
	RET

TEXT	restregs(SB), $-4
					/* LINK,SB,SP missing */
	MOVW	0x30(SP), R28
					/* R27, R26 not saved */
					/* R25, R24 missing */
	MOVW	0x44(SP), R23
	MOVW	0x48(SP), R22
	MOVW	0x4C(SP), R21
	MOVW	0x50(SP), R20
	MOVW	0x54(SP), R19
	MOVW	0x58(SP), R18
	MOVW	0x5C(SP), R17
	MOVW	0x60(SP), R16
	MOVW	0x64(SP), R15
	MOVW	0x68(SP), R14
	MOVW	0x6C(SP), R13
	MOVW	0x70(SP), R12
	MOVW	0x74(SP), R11
	MOVW	0x78(SP), R10
	MOVW	0x7C(SP), R9
	MOVW	0x80(SP), R8
	MOVW	0x84(SP), R7
	MOVW	0x88(SP), R6
	MOVW	0x8C(SP), R5
	MOVW	0x90(SP), R4
	MOVW	0x94(SP), R3
	MOVW	0x24(SP), R2
	MOVW	0x20(SP), R1
	MOVW	R2, LO
	MOVW	R1, HI
	MOVW	0x08(SP), R1
	MOVW	0x98(SP), R2
	MOVW	R1, M(STATUS)
	WAIT
	MOVW	0x9C(SP), R1
	MOVW	0x0C(SP), R26		/* old pc */
	RET

TEXT	rfnote(SB), $0
	MOVW	R1, R26			/* 1st arg is &uregpointer */
	SUBU	$(BY2WD), R26, SP	/* pc hole */
	JMP	restore
	

TEXT	clrfpintr(SB), $0
	MOVW	M(STATUS), R3
	WAIT
	OR	$CU1, R3
	MOVW	R3, M(STATUS)
	NOOP
	NOOP
	NOOP

	MOVW	FCR31, R1
	FCRNOOP
	MOVW	R1, R2
	AND	$~(0x3F<<12), R2
	MOVW	R2, FCR31

	AND	$~CU1, R3
	MOVW	R3, M(STATUS)
	WAIT
	RET

TEXT	getstatus(SB), $0
	MOVW	M(STATUS), R1
	WAIT
	RET

TEXT	savefpregs(SB), $0
	MOVW	FCR31, R2			/* 3 delays before R2 ok */
	MOVW	M(STATUS), R3
	WAIT
	AND	$~(0x3F<<12), R2, R4
	MOVW	R4, FCR31

	MOVD	F0, 0x00(R1)
	MOVD	F2, 0x08(R1)
	MOVD	F4, 0x10(R1)
	MOVD	F6, 0x18(R1)
	MOVD	F8, 0x20(R1)
	MOVD	F10, 0x28(R1)
	MOVD	F12, 0x30(R1)
	MOVD	F14, 0x38(R1)
	MOVD	F16, 0x40(R1)
	MOVD	F18, 0x48(R1)
	MOVD	F20, 0x50(R1)
	MOVD	F22, 0x58(R1)
	MOVD	F24, 0x60(R1)
	MOVD	F26, 0x68(R1)
	MOVD	F28, 0x70(R1)
	MOVD	F30, 0x78(R1)

	MOVW	R2, 0x80(R1)
	AND	$~CU1, R3
	MOVW	R3, M(STATUS)
	WAIT
	RET

TEXT	restfpregs(SB), $0

	MOVW	M(STATUS), R3
	WAIT
	OR	$CU1, R3
	MOVW	R3, M(STATUS)
	WAIT
	MOVW	fpstat+4(FP), R2
	NOOP

	MOVD	0x00(R1), F0
	MOVD	0x08(R1), F2
	MOVD	0x10(R1), F4
	MOVD	0x18(R1), F6
	MOVD	0x20(R1), F8
	MOVD	0x28(R1), F10
	MOVD	0x30(R1), F12
	MOVD	0x38(R1), F14
	MOVD	0x40(R1), F16
	MOVD	0x48(R1), F18
	MOVD	0x50(R1), F20
	MOVD	0x58(R1), F22
	MOVD	0x60(R1), F24
	MOVD	0x68(R1), F26
	MOVD	0x70(R1), F28
	MOVD	0x78(R1), F30

	MOVW	R2, FCR31
	AND	$~CU1, R3
	MOVW	R3, M(STATUS)
	WAIT
	RET

TEXT	fcr31(SB), $0

	MOVW	FCR31, R1		/* 3 delays before using R1 */
	MOVW	M(STATUS), R3
	WAIT
	AND	$~CU1, R3
	MOVW	R3, M(STATUS)
	WAIT

	RET

TEXT	prid(SB), $0

	MOVW	M(PRID), R1
	WAIT
	RET

/*
 * Emulate 68020 test and set: load linked / store conditional
 */

TEXT	tas(SB), $0
	MOVW	R1, R2		/* address of key */
tas1:
	MOVW	$1, R3
	LL(2, 1)
	NOOP
	SC(2, 3)
	NOOP
	BEQ	R3, tas1
	RET

/*
 *  cache manipulation
 */

#define	CACHE	BREAK		/* overloaded op-code */

#define	PI	R((0		/* primary I cache */
#define	PD	R((1		/* primary D cache */
#define	SD	R((3		/* secondary combined I/D cache */

#define	IWBI	(0<<2)))	/* index write-back invalidate */
#define	ILT	(1<<2)))	/* index load tag */
#define	IST	(2<<2)))	/* index store tag */
#define	CDE	(3<<2)))	/* create dirty exclusive */
#define	HI	(4<<2)))	/* hit invalidate */
#define	HWBI	(5<<2)))	/* hit write back invalidate */
#define	HWB	(6<<2)))	/* hit write back */
#define	HSV	(7<<2)))	/* hit set virtual */

/*
 *  we avoid using R4, R5, R6, and R7 so gotopc can call us without saving them
 */
TEXT	icflush(SB), $-4			/* icflush(virtaddr, count) */

	MOVW	M(STATUS), R10
	WAIT
	MOVW	4(FP), R9
	MOVW	$0, M(STATUS)
	WAIT
icflush1:			/* primary cache line size is 16 bytes */
	/*
	 * Due to a challenge bug PD+HWB DOES NOT WORK - philw
	 */
	WAIT
	WAIT
	CACHE	SD+HWBI, (R1)
	WAIT
	WAIT
	SUBU	$128, R9
	ADDU	$128, R1
	BGTZ	R9, icflush1
	MOVW	R10, M(STATUS)
	WAIT
	RET

TEXT	dcinvalidate(SB), $-4	/* dcinvalidate(virtaddr, count) */

	MOVW	M(STATUS), R10
	WAIT
	MOVW	$0, M(STATUS)
	WAIT
	MOVW	4(FP), R9
dcinval:			/* secondary cache line size is 128 bytes */
	CACHE	SD+HWBI, 0x00(R1)
	SUBU	$128, R9
	ADDU	$128, R1
	BGTZ	R9, dcinval
	MOVW	R10, M(STATUS)
	WAIT
	RET

TEXT	cleancache(SB), $-4
	MOVW	$KZERO, R1
	MOVW	M(STATUS), R10
	WAIT
	MOVW	$0, M(STATUS)
	WAIT
	MOVW	$(4*1024*1024), R9
ccache:
	CACHE	SD+IWBI, 0x00(R1)
	SUBU	$128, R9
	ADDU	$128, R1
	BGTZ	R9, ccache
	MOVW	R10, M(STATUS)
	WAIT
	RET
	
TEXT	getcallerpc(SB), $0

	MOVW	0(SP), R1
	RET

TEXT	rdcount(SB), $0

	MOVW	M(COUNT), R1
	NOOP
	RET

TEXT	wrcompare(SB), $0

	MOVW	R1, M(COMPARE)
	RET

TEXT	busprobe(SB), $-4

	NOOP
	MOVW	(R1), R2
	MOVW	$0, R1
	NOOP
	RET

TEXT	uvmove(SB), $-4

	AND	$7, R1, R2
	MOVW	4(FP), R3
	BNE	R2, uvgetuna

	/* alligned load */
	LD	(1,2)
	WAIT
	MOVW	R2, R1
	DSLL	(16,1,1)
	DSLL	(16,1,1)
	DSRA	(16,1,1)
	DSRA	(16,1,1)
uvput:
	AND	$7, R3, R4
	BNE	R4, uvputuna

	/* alligned store */
	STD	(2,3)
	NOP
	RET

	/* unalligned load */
uvgetuna:
	MOVW	0(R1),R2
	MOVW	4(R1),R1
	DSLL	(16,2,2)
	DSLL	(16,2,2)
	OR	R1, R2
	JMP	uvput

	/* unalligned store */
uvputuna:
	DSRA	(16,2,2)
	DSRA	(16,2,2)
	MOVW	R2, 0(R3)
	MOVW	R1, 4(R3)
	RET

TEXT	hack(SB), $-4

	MOVW	M(CONFIG), R1
	NOP
	RET

A carrera/main.c => carrera/main.c +341 -0
@@ 0,0 1,341 @@
#include	"u.h"
#include	"../port/lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"io.h"
#include	"init.h"

/*
 *  args passed by boot process
 */
int _argc; char **_argv; char **_env;

/*
 *  arguments passed to initcode and /boot
 */
char argbuf[128];

/*
 *  environment passed to boot -- sysname, consname, diskid
 */
char consname[NAMELEN];
char bootdisk[NAMELEN];
char screenldepth[NAMELEN];

/*
 * software tlb simulation
 */
Softtlb stlb[MAXMACH][STLBSIZE];

Conf	conf;
FPsave	initfp;

void
main(void)
{
	*(uchar*)(Uart0) = '*';
	tlbinit();		/* Very early to establish IO mappings */
	ioinit();
	arginit();
	confinit();
	savefpregs(&initfp);
	machinit();
	active.exiting = 0;
	active.machs = 1;
	kmapinit();
	xinit();
	printinit();
	NS16552setup(Uart0, UartFREQ);
	NS16552special(0, 9600, &kbdq, &printq, kbdcr2nl);
	vecinit();
	iprint("\n\nBrazil\n");
	pageinit();
	procinit0();
	initseg();
	chandevreset();
	rootfiles();
	swapinit();
	userinit();
	schedinit();
}


/*
 *  copy arguments passed by the boot kernel (or ROM) into a temporary buffer.
 *  we do this because the arguments are in memory that may be allocated
 *  to processes or kernel buffers.
 *
 *  also grab any environment variables that might be useful
 */
struct
{
	char	*name;
	char	*val;
}bootenv[] = {
	{"netaddr=",	sysname},
	{"console=",	consname},
	{"bootdisk=",	bootdisk},
	{"ldepth=",	screenldepth},
};
char *sp;

char *
pusharg(char *p)
{
	int n;

	n = strlen(p)+1;
	sp -= n;
	memmove(sp, p, n);
	return sp;
}

void
arginit(void)
{
	int i, n;
	char **av;

	/*
	 *  get boot env variables
	 */
	if(*sysname == 0)
		for(av = _env; *av; av++)
			for(i=0; i < sizeof bootenv/sizeof bootenv[0]; i++){
				n = strlen(bootenv[i].name);
				if(strncmp(*av, bootenv[i].name, n) == 0){
					strncpy(bootenv[i].val, (*av)+n, NAMELEN);
					bootenv[i].val[NAMELEN-1] = '\0';
					break;
				}
			}

	/*
	 *  pack args into buffer
	 */
	av = (char**)argbuf;
	sp = argbuf + sizeof(argbuf);
	for(i = 0; i < _argc; i++){
		if(strchr(_argv[i], '='))
			break;
		av[i] = pusharg(_argv[i]);
	}
	av[i] = 0;
}

/*
 *  initialize a processor's mach structure.  each processor does this
 *  for itself.
 */
void
machinit(void)
{
	int n;

	/* Ensure CU1 is off */
	clrfpintr();

	/* scrub cache */
	cleancache();

	n = m->machno;
	m->stb = &stlb[n][0];
	clockinit();
}

/*
 * Map IO address space in wired down TLB entry 1
 */
void
ioinit(void)
{
	ulong phys;

	phys = PPN(Devicephys)|PTEGLOBL|PTEVALID|PTEWRITE|PTEUNCACHED;

	puttlbx(1, Devicevirt, phys, PTEGLOBL, PGSZ256K);
}

/*
 *  setup MIPS trap vectors
 */
void
vecinit(void)
{
	memmove((ulong*)UTLBMISS, (ulong*)vector0, 0x100);
	memmove((ulong*)CACHETRAP, (ulong*)vector100, 0x80);
	memmove((ulong*)EXCEPTION, (ulong*)vector180, 0x80);
	icflush((ulong*)UTLBMISS, 32*1024);
}

void
init0(void)
{
	char buf[2*NAMELEN];

	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);
	up->dot = clone(up->slash, 0);

	iallocinit();
	chandevinit();

	if(!waserror()){
		ksetenv("cputype", "mips");
		sprint(buf, "sgi %s 4D", conffile);
		ksetenv("terminal", buf);
		ksetenv("sysname", sysname);
		poperror();
	}

	kproc("alarm", alarmkproc, 0);
	touser((uchar*)(USTKTOP-sizeof(argbuf)));
}

FPsave	initfp;

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

	p = newproc();
	p->pgrp = newpgrp();
	p->egrp = smalloc(sizeof(Egrp));
	p->egrp->ref = 1;
	p->fgrp = smalloc(sizeof(Fgrp));
	p->fgrp->ref = 1;
	p->procmode = 0640;

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

	p->fpstate = FPinit;
	p->fpsave.fpstatus = initfp.fpstatus;

	/*
	 * Kernel Stack
	 */
	p->sched.pc = (ulong)init0;
	p->sched.sp = (ulong)p->kstack+KSTACK-(1+MAXSYSARG)*BY2WD;
	/*
	 * User Stack, pass input arguments to boot process
	 */
	s = newseg(SG_STACK, USTKTOP-USTKSIZE, USTKSIZE/BY2PG);
	p->seg[SSEG] = s;
	pg = newpage(1, 0, USTKTOP-BY2PG);
	segpage(s, pg);
	k = kmap(pg);
	for(av = (char**)argbuf; *av; av++)
		*av += (USTKTOP - sizeof(argbuf)) - (ulong)argbuf;

	memmove((uchar*)VA(k) + BY2PG - sizeof(argbuf), argbuf, sizeof argbuf);
	kunmap(k);

	/* 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(long type)
{
	int timer;

	spllo();
	print("cpu %d exiting %d\n", m->machno, type);
	timer = 0;
	while(active.machs || consactive()) {
		if(timer++ > 400)
			break;
		delay(10);
	}
	splhi();
	for(;;)
		;
}

void
confinit(void)
{
	ulong ktop, top;

	/*
	 *  divide memory twixt user pages and kernel. Since
	 *  the kernel can't use anything above .5G unmapped,
	 *  make sure all that memory goes to the user.
	 */
	ktop = PGROUND((ulong)end);
	ktop = PADDR(ktop);
	top = (16*1024*1024)/BY2PG;

	conf.base0 = 0;
	conf.npage0 = top;
	conf.npage = conf.npage0;
	conf.npage0 -= ktop/BY2PG;
	conf.base0 += ktop;
	conf.npage1 = 0;
	conf.base1 = 0;

	conf.upages = (conf.npage*90)/100;
	if(top - conf.upages > (256*1024*1024)/BY2PG)
		conf.upages = top - (256*1024*1024)/BY2PG;

	conf.nmach = 1;

	/* set up other configuration parameters */
	conf.nproc = 100;
	conf.nswap = 262144;
	conf.nimage = 200;
	conf.ipif = 8;
	conf.ip = 64;
	conf.arp = 32;
	conf.frag = 32;

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


/*
 *  for the sake of devcons
 */
void
lights(int v)
{
	USED(v);
}

void
buzz(int f, int d)
{
	USED(f);
	USED(d);
}

int
mouseputc(IOQ *q, int c)
{
	USED(q);
	USED(c);
	return 0;
}


A carrera/mem.h => carrera/mem.h +187 -0
@@ 0,0 1,187 @@
/*
 * Memory and machine-specific definitions.  Used in C and assembler.
 */

/*
 * Sizes
 */

#define	BI2BY		8			/* bits per byte */
#define BI2WD		32			/* bits per word */
#define	BY2WD		4			/* bytes per word */
#define	BY2PG		4096			/* bytes per page */
#define	WD2PG		(BY2PG/BY2WD)		/* words per page */
#define	PGSHIFT		12			/* log(BY2PG) */
#define PGROUND(s)	(((s)+(BY2PG-1))&~(BY2PG-1))

#define	MAXMACH		4			/* max # cpus system can run */
#define KSTACK		4096			/* Size of kernel stack */

/*
 * Time
 */
#define HZ		100			/* clock frequency */
#define	MS2HZ		(1000/HZ)		/* millisec per clock tick */
#define	TK2SEC(t)	((t)/HZ)		/* ticks to seconds */
#define	TK2MS(t)	((t)*MS2HZ)		/* ticks to milliseconds */
#define	MS2TK(t)	((t)/MS2HZ)		/* milliseconds to ticks */

/*
 * CP0 registers
 */

#define INDEX		0
#define RANDOM		1
#define TLBPHYS0	2
#define TLBPHYS1	3
#define CONTEXT		4
#define PAGEMASK	5
#define WIRED		6
#define BADVADDR	8
#define COUNT		9
#define TLBVIRT		10
#define COMPARE		11
#define STATUS		12
#define CAUSE		13
#define EPC		14
#define	PRID		15
#define	CONFIG		16
#define	LLADDR		17
#define	WATCHLO		18
#define	WATCHHI		19
#define	CACHEECC	26
#define	CACHEERR	27
#define	TAGLO		28
#define	TAGHI		29
#define	ERROREPC	30

/*
 * M(STATUS) bits
 */
#define KMODEMASK	0x0000001f
#define IE		0x00000001
#define EXL		0x00000002
#define ERL		0x00000004
#define KSUPER		0x00000008
#define KUSER		0x00000010
#define INTMASK		0x0000ff00
#define INTR0		0x00000100
#define INTR1		0x00000200
#define INTR2		0x00000400
#define INTR3		0x00000800
#define INTR4		0x00001000
#define INTR5		0x00002000
#define INTR6		0x00004000
#define INTR7		0x00008000
#define ISC		0x00010000
#define SWC		0x00020000
#define CU1		0x20000000

/*
 * Traps
 */

#define	UTLBMISS	(KSEG0+0x000)
#define	XEXCEPTION	(KSEG0+0x80)
#define	CACHETRAP	(KSEG0+0x100)
#define	EXCEPTION	(KSEG0+0x180)

/*
 * Magic registers
 */

#define	USER		24		/* R24 is up-> */
#define	MACH		25		/* R25 is m-> */

/*
 * Fundamental addresses
 */
#define	MACHADDR	0x80005000	/* Mach structures */
/* Leave space below kmap for IO */
#define	KMAPADDR	0xE0040000
/* Sizeof(Ureg)+space for retpc & ur */
#define UREGSIZE	0xA0
#define	MACHP(n)	((Mach *)(MACHADDR+(n)*BY2PG))


/*
 * MMU
 */

#define PGSZ4K		(0x00<<13)
#define PGSZ256K	(0x3F<<13)
	
#define	KUSEG	0x00000000
#define KSEG0	0x80000000
#define KSEG1	0xA0000000
#define	KSEG2	0xC0000000
#define	KSEG3	0xE0000000
#define	KSEGM	0xE0000000	/* mask to check which seg */

#define PIDXSHFT	12
#define PIDX		(0x7<<PIDXSHFT)
#define KMAPSHIFT	15
#define NCOLOR		8
#define getcolor(a)	(((ulong)(a)>>PIDXSHFT)&7)

#define	PTEGLOBL	(1<<0)
#define	PTEVALID	(1<<1)
#define	PTEWRITE	(1<<2)
#define PTERONLY	0
#define PTEALGMASK	(7<<3)
#define PTEUNCACHED	(2<<3)
#define PTENONCOHER	(3<<3)
#define PTECOHERXCL	(4<<3)
#define PTECOHERXCLW	(5<<3)
#define PTECOHERUPDW	(6<<3)

#define	PTEPID(n)	(n)
#define TLBPID(n)	((n)&0xFF)
#define PTEMAPMEM	(1024*1024)	
#define	PTEPERTAB	(PTEMAPMEM/BY2PG)
#define STLBLOG		13
#define STLBSIZE	(1<<STLBLOG)
#define KPTELOG		8
#define KPTESIZE	(1<<KPTELOG)
#define SEGMAPSIZE	512

#define	NTLBPID	256	/* number of pids */
#define	NTLB	48	/* number of entries */
#define	TLBROFF	4	/* offset of first randomly indexed entry */

/*
 * Address spaces
 */

#define	UZERO	KUSEG			/* base of user address space */
#define	UTZERO	(UZERO+BY2PG)		/* first address in user text */
#define	USTKTOP	(KZERO-BY2PG)		/* byte just beyond user stack */
#define	TSTKTOP	(0xC0000000+USTKSIZE-BY2PG) /* top of temporary stack */
#define TSTKSIZ 100
#define	KZERO	KSEG0			/* base of kernel address space */
#define	KTZERO	(KZERO+0x20000)		/* first address in kernel text */
#define	USTKSIZE	(4*1024*1024)	/* size of user stack */
/*
 * Exception codes
 */
#define	EXCMASK	0x1f		/* mask of all causes */
#define	CINT	 0		/* external interrupt */
#define	CTLBM	 1		/* TLB modification */
#define	CTLBL	 2		/* TLB miss (load or fetch) */
#define	CTLBS	 3		/* TLB miss (store) */
#define	CADREL	 4		/* address error (load or fetch) */
#define	CADRES	 5		/* address error (store) */
#define	CBUSI	 6		/* bus error (fetch) */
#define	CBUSD	 7		/* bus error (data load or store) */
#define	CSYS	 8		/* system call */
#define	CBRK	 9		/* breakpoint */
#define	CRES	10		/* reserved instruction */
#define	CCPU	11		/* coprocessor unusable */
#define	COVF	12		/* arithmetic overflow */
#define	CTRAP	13		/* trap */
#define	CVCEI	14		/* virtual coherence exception (instruction) */
#define	CFPE	15		/* floating point exception */
#define	CWATCH	23		/* watch exception */
#define	CVCED	31		/* virtual coherence exception (data) */

#define isphys(x) (((ulong)x&KSEGM)==KSEG0 || ((ulong)x&KSEGM)==KSEG1)

A carrera/mmu.c => carrera/mmu.c +369 -0
@@ 0,0 1,369 @@
#include	"u.h"
#include	"../port/lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"

/*
 *  tlb entry 0 is used only by mmuswitch() to set the current tlb pid.
 */

/*
 *  Kmap entries start at tlb index 1 and work their way up until
 *  kmapinval() removes them.  They then restart at 1.  As long as there
 *  are few kmap entries they will not pass TLBROFF (the WIRED tlb entry
 *  limit) and interfere with user tlb entries.
 */

/*
 *  All invalidations of the tlb are via indexed entries.  The virtual
 *  address used is always 'KZERO | (x<<(PGSHIFT+1) | currentpid' where
 *  'x' is the index into the tlb.  This ensures that the current pid doesn't
 *  change and that no two invalidated entries have matching virtual
 *  addresses just in case SGI/MIPS ever makes a chip that cares (as
 *  they keep threatening).  These entries should never be used in
 *  lookups since accesses to KZERO addresses don't go through the tlb.
 */

#define TLBINVAL(x, pid) puttlbx(x, KZERO|((x)<<(PGSHIFT+1))|(pid), 0, 0, PGSZ4K)

void
tlbinit(void)
{
	int i;

	for(i=0; i<NTLB; i++)
		TLBINVAL(i, 0);
}

Lock	kmaplock;
KMap	kpte[KPTESIZE];
KMap*	kmapfree;

void
kmapinit(void)
{
	KMap *k, *klast;

	lock(&kmaplock);
	kmapfree = kpte;
	klast = &kpte[KPTESIZE-1];
	for(k=kpte; k<klast; k++)
		k->next = k+1;
	k->next = 0;
	unlock(&kmaplock);
}

/*
 *  Arrange that the KMap'd virtual address will hit the same
 *  primary cache line as pg->va by making bits 14...12 of the
 *  tag the same as virtual address.  These bits are the index
 *  into the primary cache and are checked whenever accessing
 *  the secondary cache through the primary.  Violation causes
 *  a VCE trap.
 */
KMap *
kmap(Page *pg)
{
	int s;
	KMap *k;
	ulong pte;
	ulong x, virt;

	s = splhi();
	lock(&kmaplock);

	if(kmapfree == 0)
		panic("out of kmap");

	k = kmapfree;
	kmapfree = k->next;

	k->pg = pg;
	/* One for the allocation,
	 * One for kactive
	 */
	k->ref = 2;
	k->konmach[m->machno] = m->kactive;
	m->kactive = k;

	virt = pg->va;
	/* bits 14..12 form the secondary-cache virtual index */
	virt &= PIDX;	
	virt |= KMAPADDR | ((k-kpte)<<KMAPSHIFT);

	k->virt = virt;
	pte = PPN(pg->pa)|PTECOHERXCLW|PTEGLOBL|PTEWRITE|PTEVALID;
	if(virt & BY2PG) {
		k->phys0 = PTEGLOBL;
		k->phys1 = pte;
	}
	else {
		k->phys0 = pte;
		k->phys1 = PTEGLOBL;
	}

	x = m->ktlbnext;
	puttlbx(x, (virt & ~BY2PG)|TLBPID(tlbvirt()), k->phys0, k->phys1, PGSZ4K);
	m->ktlbx[x] = 1;
	if(++x >= NTLB)
		m->ktlbnext = 1;
	else
		m->ktlbnext = x;

	unlock(&kmaplock);

	splx(s);
	return k;
}

void
kunmap(KMap *k)
{
	int s;

	s = splhi();
	if(decref(k) == 0) {
		k->virt = 0;
		k->phys0 = 0;
		k->phys1 = 0;
		k->pg = 0;

		lock(&kmaplock);
		k->next = kmapfree;
		kmapfree = k;
		unlock(&kmaplock);
	}
	splx(s);
}

void
kfault(ulong addr)
{
	KMap *k, *f;
	ulong x, index;

	index = (addr & ~KSEGM) >> KMAPSHIFT;
	if(index >= KPTESIZE)
		panic("kmapfault: %lux", addr);

	k = &kpte[index];
	if(k->virt == 0)
		panic("kmapfault: unmapped %lux", addr);

	for(f = m->kactive; f; f = f->konmach[m->machno])
		if(f == k)
			break;
	if(f == 0) {
		incref(k);
		k->konmach[m->machno] = m->kactive;
		m->kactive = k;
	}

	x = m->ktlbnext;
	puttlbx(x, (k->virt & ~BY2PG)|TLBPID(tlbvirt()), k->phys0, k->phys1, PGSZ4K);
	m->ktlbx[x] = 1;
	if(++x >= NTLB)
		m->ktlbnext = 1;
	else
		m->ktlbnext = x;
}

void
kmapinval()
{
	int mno, i;
	KMap *k, *next;
	int curpid;
	uchar *ktlbx;


	if(m->kactive == 0)
		return;

	curpid = PTEPID(TLBPID(tlbvirt()));
	ktlbx = m->ktlbx;
	for(i = 0; i < NTLB; i++, ktlbx++){
		if(*ktlbx == 0)
			continue;
		TLBINVAL(i, curpid);
		*ktlbx = 0;
	}

	mno = m->machno;
	for(k = m->kactive; k; k = next) {
		next = k->konmach[mno];
		kunmap(k);
	}
	m->kactive = 0;
	m->ktlbnext = 1;
}

void
mmuswitch(Proc *p)
{
	int tp;

	if(p->newtlb) {
		memset(p->pidonmach, 0, sizeof p->pidonmach);
		p->newtlb = 0;
	}
	tp = p->pidonmach[m->machno];
	if(tp == 0)
		tp = newtlbpid(p);
	puttlbx(0, KZERO|PTEPID(tp), 0, 0, PGSZ4K);
}

void
mmurelease(Proc *p)
{
	memset(p->pidonmach, 0, sizeof p->pidonmach);
}

/*
 * Process must be splhi
 */
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])
		purgetlb(i);
	if(h[i] != 0)
		panic("newtlb");

	m->pidproc[i] = p;
	p->pidonmach[m->machno] = i;
	m->lastpid = i;

	return i;
}

void
putmmu(ulong tlbvirt, ulong tlbphys, Page *pg)
{
	short tp;
	char *ctl;
	Softtlb *entry;
	int s;

	s = splhi();
	tp = up->pidonmach[m->machno];
	if(tp == 0)
		tp = newtlbpid(up);

	tlbvirt |= PTEPID(tp);
	if((tlbphys & PTEALGMASK) != PTEUNCACHED) {
		tlbphys &= ~PTEALGMASK;
		tlbphys |= PTECOHERXCLW;
	}

	entry = putstlb(tlbvirt, tlbphys);
	puttlb(entry->virt, entry->phys0, entry->phys1);

	ctl = &pg->cachectl[m->machno];
	if(*ctl == PG_TXTFLUSH) {
		icflush((void*)pg->va, BY2PG);
		*ctl = PG_NOFLUSH;
	}
	splx(s);
}

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

	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 = 0;

	/*
	 * clean up the hardware
	 */
	for(i=TLBROFF; i<NTLB; i++)
		if(pidproc[TLBPID(gettlbvirt(i))] == 0)
			TLBINVAL(i, pid);
}

void
flushmmu(void)
{
	int s;

	s = splhi();
	up->newtlb = 1;
	mmuswitch(up);
	splx(s);
}

void
clearmmucache(void)
{
}

Softtlb*
putstlb(ulong tlbvirt, ulong tlbphys)
{
	int k;
	Softtlb *entry;

	k = tlbvirt & BY2PG;
	tlbvirt &= ~BY2PG;

	entry = &m->stb[(tlbvirt ^ (tlbvirt>>13)) & (STLBSIZE-1)];
	if(entry->virt != tlbvirt) {
		entry->virt = tlbvirt;
		entry->phys0 = 0;
		entry->phys1 = 0;
	}

	if(k)
		entry->phys1 = tlbphys;
	else
		entry->phys0 = tlbphys;

	if(entry->phys0 == 0 && entry->phys1 == 0)
		entry->virt = 0;

	return entry;
}

A carrera/segment.h => carrera/segment.h +10 -0
@@ 0,0 1,10 @@
/*
 * Attach segment types
 */

Physseg physseg[] =
{
	{ SG_SHARED,	"shared",	0,	SEGMAXSIZE,	0, 0 },
	{ SG_BSS,	"memory",	0,	SEGMAXSIZE,	0, 0 },
	{ 0,		0,		0,	0,		0, 0 },
};

A carrera/trap.c => carrera/trap.c +625 -0
@@ 0,0 1,625 @@
#include	"u.h"
#include	"../port/lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"ureg.h"
#include	"io.h"
#include	"../port/error.h"

void	noted(Ureg**, ulong);
void	rfnote(Ureg**);
void	kernfault(Ureg*, int);

char *excname[] =
{
	"trap: external interrupt",
	"trap: TLB modification",
	"trap: TLB miss (load or fetch)",
	"trap: TLB miss (store)",
	"trap: address error (load or fetch)",
	"trap: address error (store)",
	"trap: bus error (fetch)",
	"trap: bus error (data load or store)",
	"trap: system call",
	"breakpoint",
	"trap: reserved instruction",
	"trap: coprocessor unusable",
	"trap: arithmetic overflow",
	"trap: TRAP exception",
	"trap: VCE (instruction)",
	"trap: floating-point exception",
	"trap: undefined 16",	/* used as sys call for debugger */
	"trap: undefined 17",
	"trap: undefined 18",
	"trap: undefined 19",
	"trap: undefined 20",
	"trap: undefined 21",
	"trap: undefined 22",
	"trap: WATCH exception",
	"trap: undefined 24",
	"trap: undefined 25",
	"trap: undefined 26",
	"trap: undefined 27",
	"trap: undefined 28",
	"trap: undefined 29",
	"trap: undefined 30",
	"trap: VCE (data)",
};

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


char *regname[]={
	"STATUS",	"PC",
	"SP",		"CAUSE",
	"BADADDR",	"TLBVIRT",
	"HI",		"LO",
	"R31",		"R30",
	"R28",		"R27",
	"R26",		"R25",
	"R24",		"R23",
	"R22",		"R21",
	"R20",		"R19",
	"R18",		"R17",
	"R16",		"R15",
	"R14",		"R13",
	"R12",		"R11",
	"R10",		"R9",
	"R8",		"R7",
	"R6",		"R5",
	"R4",		"R3",
	"R2",		"R1",
};

static char *
ptlb(ulong phys)
{
	static char buf[4][32];
	static int k;
	char *p;

	k = (k+1)&3;
	p = buf[k];
	p += sprint(p, "(0x%ux %d ", (phys<<6) & ~(BY2PG-1), (phys>>3)&7);
	if(phys & 4)
		*p++ = 'd';
	if(phys & 2)
		*p++ = 'v';
	if(phys & 1)
		*p++ = 'g';
	*p++ = ')';
	*p = 0;
	return buf[k];
}

static void
kpteprint(Ureg *ur)
{
	ulong i, tlbstuff[3];
	KMap *k;

	i = (ur->badvaddr & ~(2*BY2PG-1)) | TLBPID(tlbvirt());
	print("tlbvirt=0x%ux\n", i);
	i = gettlbp(i, tlbstuff);
	print("i=%d v=0x%ux p0=%s p1=%s\n",
		i, tlbstuff[0], ptlb(tlbstuff[1]), ptlb(tlbstuff[2]));

	i = (ur->badvaddr & ~KMAPADDR)>>15;
	if(i > KPTESIZE){
		print("kpte index = 0x%ux ?\n", i);
		return;
	}
	k = &kpte[i];
	print("i=%d, &k=0x%ux, k={v=0x%ux, p0=%s, p1=%s, pg=0x%ux}\n",
		i, k, k->virt, ptlb(k->phys0), ptlb(k->phys1), k->pg);
	print("pg={pa=0x%ux, va=0x%ux}\n", k->pg->pa, k->pg->va);
}

void
kvce(Ureg *ur, int ecode)
{
	char c;
	Pte **p;
	Page **pg;
	Segment *s;
	ulong addr, soff;

	c = 'D';
	if(ecode == CVCEI)
		c = 'I';
	print("Trap: VCE%c: addr=0x%ux\n", c, ur->badvaddr);
	if((ur->badvaddr & KSEGM) == KSEG3) {
		kpteprint(ur);
		return;
	}
	if(up && !(ur->badvaddr & KSEGM)) {
		addr = ur->badvaddr;
		s = seg(up, addr, 0);
		if(s == 0){
			print("no s\n");
			for(;;);
		}
		addr &= ~(BY2PG-1);
		soff = addr-s->base;
		p = &s->map[soff/PTEMAPMEM];
		if(*p){
			pg = &(*p)->pages[(soff&(PTEMAPMEM-1))/BY2PG];
			if(*pg) {
				print("pa=0x%ux, va=0x%ux\n",
					(*pg)->pa, (*pg)->va);
			} else
				print("no *pg\n");
		}else
			print("no *p\n");
	}
}

void
trap(Ureg *ur)
{
	int ecode;
	ulong fpfcr31;
	int user, cop, x, fpchk;
	char buf[2*ERRLEN], buf1[ERRLEN], *fpexcep;

	ecode = (ur->cause>>2)&EXCMASK;
	user = ur->status&KUSER;

	fpchk = 0;
	if(user){
		up->dbgreg = ur;
		if(up && up->fpstate == FPactive) {
			if((ur->status&CU1) == 0)		/* Paranoid */
				panic("FPactive but no CU1");
			ur->status &= ~CU1;
			up->fpstate = FPinactive;
			savefpregs(&up->fpsave);
		}
	}

	switch(ecode){
	case CINT:
		intr(ur);
		break;

	case CFPE:
		fptrap(ur);
		clrfpintr();
		fpchk = 1;
		break;

	case CTLBM:
	case CTLBL:
	case CTLBS:
		if(up == 0)
			kernfault(ur, ecode);

		if(!user && (ur->badvaddr & KSEGM) == KSEG3) {
			kfault(ur->badvaddr);
			break;
		}

		x = up->insyscall;
		up->insyscall = 1;
		spllo();
		faultmips(ur, user, ecode);
		up->insyscall = x;
		break;

	case CVCEI:
	case CVCED:
		kvce(ur, ecode);
		goto Default;

	case CCPU:
		cop = (ur->cause>>28)&3;
		if(user && up && cop == 1) {
			if(up->fpstate == FPinit) {
				up->fpstate = FPinactive;
				fpfcr31 = up->fpsave.fpstatus;
				up->fpsave = initfp;
				up->fpsave.fpstatus = fpfcr31;
				break;
			}
			if(up->fpstate == FPinactive)
				break;
		}
		/* Fallthrough */

	Default:
	default:
		if(user) {
			spllo();
			sprint(buf, "sys: %s", excname[ecode]);
			postnote(up, 1, buf, NDebug);
			break;
		}
		print("kernel%d %s pc=%lux\n", m->machno, excname[ecode], ur->pc);
		dumpregs(ur);
		dumpstack();
		if(m->machno == 0)
			spllo();
		exit(1);
	}

	if(fpchk) {
		fpfcr31 = up->fpsave.fpstatus;
		if((fpfcr31>>12) & ((fpfcr31>>7)|0x20) & 0x3f) {
			spllo();
			fpexcep	= fpexcname(ur, fpfcr31, buf1);
			sprint(buf, "sys: fp: %s", fpexcep);
			postnote(up, 1, buf, NDebug);
		}
	}


	splhi();
	if(!user)
		return;

	notify(ur);
	if(up->fpstate == FPinactive) {
		restfpregs(&up->fpsave, up->fpsave.fpstatus&~FPEXPMASK);
		up->fpstate = FPactive;
		ur->status |= CU1;
	}
}

void
intr(Ureg *ur)
{
	ulong cause = ur->cause;

	m->intr++;
	cause &= INTR7|INTR6|INTR5|INTR4|INTR3|INTR2|INTR1|INTR0;

	iprint("intr %lux\n", cause);
}

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

	fppc = ur->pc;
	if(ur->cause & (1<<31))	/* branch delay */
		fppc += 4;
	s = 0;
	if(fcr31 & (1<<17))
		s = "unimplemented operation";
	else{
		fcr31 >>= 7;		/* trap enable bits */
		fcr31 &= (fcr31>>5);	/* anded with exceptions */
		for(i=0; i<5; i++)
			if(fcr31 & (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)
{
	print("panic: kfault %s badvaddr=0x%lux\n", excname[code], ur->badvaddr);
	kpteprint(ur);
	print("u=0x%lux status=0x%lux pc=0x%lux sp=0x%lux\n",
				up, ur->status, ur->pc, ur->sp);
	panic("kfault");
}

void
dumpstack(void)
{
	ulong l, v, top;
	extern ulong etext;

	if(up == 0)
		return;

	top = (ulong)up->kstack + KSTACK;
	for(l=(ulong)&l; l < top; l += BY2WD) {
		v = *(ulong*)l;
		if(KTZERO < v && v < (ulong)&etext) {
			print("%lux=%lux\n", l, v);
			delay(100);
		}
	}
}

void
dumpregs(Ureg *ur)
{
	int i;
	ulong *l;
	if(up)
		print("registers for %s %d\n", up->text, up->pid);
	else
		print("registers for kernel\n");

	l = &ur->status;
	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]);
}

int
notify(Ureg *ur)
{
	int l;
	ulong sp;
	Note *n;

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

	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%lux", ur->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);
	}
	up->svstatus = ur->status;
	sp = ur->usp - sizeof(Ureg);

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

	up->ureg = (void*)sp;
	memmove((Ureg*)sp, ur, sizeof(Ureg));
	sp -= ERRLEN;
	memmove((char*)sp, up->note[0].msg, ERRLEN);
	sp -= 3*BY2WD;
	*(ulong*)(sp+2*BY2WD) = sp+3*BY2WD;	/* arg 2 is string */
	up->svr1 = ur->r1;			/* save away r1 */
	ur->r1 = (ulong)up->ureg;		/* arg 1 is ureg* */
	*(ulong*)(sp+0*BY2WD) = 0;		/* arg 0 is pc */
	ur->usp = sp;
	ur->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);
	splhi();
	return 1;
}

/*
 * Return user to state before notify()
 */
void
noted(Ureg **urp, ulong arg0)
{
	Ureg *nur;

	nur = up->ureg;
	if(nur->status!=up->svstatus) {
		pprint("bad noted ureg status %lux\n", nur->status);
		pexit("Suicide", 0);
	}
	qlock(&up->debug);
	if(!up->notified) {
		qunlock(&up->debug);
		pprint("call to noted() when not notified\n");
		pexit("Suicide", 0);
	}
	up->notified = 0;
	memmove(*urp, up->ureg, sizeof(Ureg));
	(*urp)->r1 = up->svr1;
	switch(arg0) {
	case NCONT:
		if(!okaddr(nur->pc, 1, 0) || !okaddr(nur->usp, BY2WD, 0)){
			pprint("suicide: trap in noted\n");
			qunlock(&up->debug);
			pexit("Suicide", 0);
		}
		splhi();
		qunlock(&up->debug);
		rfnote(urp);
		break;

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

#include "../port/systab.h"

long
syscall(Ureg *aur)
{
	long ret;
	ulong sp;
	Ureg *ur;

	m->syscall++;
	up->insyscall = 1;
	ur = aur;
	up->pc = ur->pc;
	up->dbgreg = aur;
	ur->cause = 16<<2;	/* for debugging: system call is undef 16 */

	if(up->fpstate == FPactive) {
		if((ur->status&CU1) == 0)
			panic("syscall: FPactive but no CU1");
		up->fpsave.fpstatus = fcr31();
		up->fpstate = FPinit;
		ur->status &= ~CU1;
	}
	spllo();

	if(up->procctl)
		procctl(up);

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

		if(sp & (BY2WD-1)){
			pprint("odd sp in sys call pc %lux sp %lux\n", ur->pc, ur->sp);
			postnote(up, 1, "sys: odd stack", NDebug);
			error(Ebadarg);
		}

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

		up->s = *((Sargs*)(sp+BY2WD));
		up->psstate = sysctab[up->scallnr];
		ret = (*systab[up->scallnr])(up->s.args);
		poperror();
	}
	ur->pc += 4;
	up->nerrlab = 0;
	up->psstate = 0;
	up->insyscall = 0;
	if(up->scallnr == NOTED)			/* ugly hack */
		noted(&aur, *(ulong*)(sp+BY2WD));	/* doesn't return */

	splhi();
	if(up->scallnr!=RFORK && (up->procctl || up->nnote)){
		ur->r1 = ret;			/* load up for noted() */
		if(notify(ur))
			return ur->r1;
	}
	return ret;
}

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

	p->sched.sp = (ulong)p->kstack+KSTACK-(sizeof(Ureg)+2*BY2WD);
	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;
}

static
void
linkproc(void)
{
	spllo();
	(*up->kpfun)(up->kparg);
}

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

	p->kpfun = func;
	p->kparg = arg;
}

long
execregs(ulong entry, ulong ssize, ulong nargs)
{
	Ureg *ur;
	ulong *sp;

	sp = (ulong*)(USTKTOP - ssize);
	*--sp = nargs;

	ur = (Ureg*)up->dbgreg;
	ur->usp = (ulong)sp;
	ur->pc = entry - 4;		/* syscall advances it */
	up->fpsave.fpstatus = initfp.fpstatus;
	return USTKTOP-BY2WD;		/* address of user-level clock */
}

ulong
userpc(void)
{
	Ureg *ur;

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

/* 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 *xp, char *pureg, char *uva, int n)
{
	ulong status;

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

M port/segment.c => port/segment.c +2 -0
@@ 476,6 476,8 @@ syssegflush(ulong *arg)
	j = (soff&(PTEMAPMEM-1))/BY2PG;
	len = arg[1]+BY2PG;

print("%s segflush 0x%lux %d\n", up->text, arg[0], arg[1]);

	for(i = soff/PTEMAPMEM; len > 0 && i < SEGMAPSIZE; i++) {
		if(s->map[i] == 0) {
			len -= PTEMAPMEM;