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 = ðer.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 < ðer.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(ðer, "ether", Ntypes, 32*1024);
+ ether.alen = 6;
+ memmove(ether.addr, ether.ea, 6);
+ memmove(ether.bcast, etherbcast, 6);
+ ether.promiscuous = promiscuous;
+ ether.arg = ðer;
+}
+
+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(ðer, c, name);
+}
+
+Chan*
+etheropen(Chan *c, int omode)
+{
+ return netifopen(ðer, c, omode);
+}
+
+void
+ethercreate(Chan *c, char *name, int omode, ulong perm)
+{
+ USED(c, name, omode, perm);
+}
+
+void
+etherclose(Chan *c)
+{
+ netifclose(ðer, c);
+}
+
+long
+etherread(Chan *c, void *buf, long n, ulong offset)
+{
+ return netifread(ðer, 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(ðer, c, buf, n);
+
+ /* we handle data */
+ qlock(ðer.tlock);
+ tsleep(ðer.tr, isoutbuf, edlc, 10000);
+ if(!isoutbuf(edlc)){
+ print("ether transmitter jammed\n");
+ } else {
+ p = ðer.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(ðer.tlock);
+ return n;
+}
+
+void
+etherremove(Chan *c)
+{
+ USED(c);
+}
+
+void
+etherstat(Chan *c, char *dp)
+{
+ netifstat(ðer, c, dp);
+}
+
+void
+etherwstat(Chan *c, char *dp)
+{
+ netifwstat(ðer, 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;