From 51b7b955243a05c2c48c39f8ce3617f30a622771 Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Fri, 3 Sep 1993 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 1993-09-03 --- carrera/clock.c | 100 +++++ carrera/dat.h | 169 +++++++++ carrera/devether.c | 462 ++++++++++++++++++++++++ carrera/faultmips.c | 160 ++++++++ carrera/fns.h | 115 ++++++ carrera/fptrap.c | 283 +++++++++++++++ carrera/io.h | 28 ++ carrera/l.s | 863 ++++++++++++++++++++++++++++++++++++++++++++ carrera/main.c | 341 +++++++++++++++++ carrera/mem.h | 187 ++++++++++ carrera/mmu.c | 369 +++++++++++++++++++ carrera/segment.h | 10 + carrera/trap.c | 625 ++++++++++++++++++++++++++++++++ port/segment.c | 2 + 14 files changed, 3714 insertions(+) create mode 100644 carrera/clock.c create mode 100644 carrera/dat.h create mode 100644 carrera/devether.c create mode 100644 carrera/faultmips.c create mode 100644 carrera/fns.h create mode 100644 carrera/fptrap.c create mode 100644 carrera/io.h create mode 100644 carrera/l.s create mode 100644 carrera/main.c create mode 100644 carrera/mem.h create mode 100644 carrera/mmu.c create mode 100644 carrera/segment.h create mode 100644 carrera/trap.c diff --git a/carrera/clock.c b/carrera/clock.c new file mode 100644 index 0000000000000000000000000000000000000000..75f819f3b7be344940f1accaf23f2c44e22a17f7 --- /dev/null +++ b/carrera/clock.c @@ -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; iproc; + if(p) { + p->time[p->insyscall]++; + nrun++; + } + } + } + nrun = (nrdy+nrun)*1000; + m->load = (m->load*19+nrun)/20; + } + + kmapinval(); + + if((active.machs&(1<machno)) == 0) + return; + + if(active.exiting && (active.machs & (1<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); +} diff --git a/carrera/dat.h b/carrera/dat.h new file mode 100644 index 0000000000000000000000000000000000000000..4d627f608f9886b2602c6e60e0f0b69ee27b5e29 --- /dev/null +++ b/carrera/dat.h @@ -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; diff --git a/carrera/devether.c b/carrera/devether.c new file mode 100644 index 0000000000000000000000000000000000000000..c5b95c0b9c1ace99567808b2799a978c4230e236 --- /dev/null +++ b/carrera/devether.c @@ -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<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); +} diff --git a/carrera/faultmips.c b/carrera/faultmips.c new file mode 100644 index 0000000000000000000000000000000000000000..bea26573f6307fa1ef56befd0b2ec6cf8574d717 --- /dev/null +++ b/carrera/faultmips.c @@ -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); + } +} diff --git a/carrera/fns.h b/carrera/fns.h new file mode 100644 index 0000000000000000000000000000000000000000..e32a5539c0d246279e28d20d3eb3a57c8653d71b --- /dev/null +++ b/carrera/fns.h @@ -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) diff --git a/carrera/fptrap.c b/carrera/fptrap.c new file mode 100644 index 0000000000000000000000000000000000000000..bdf9ea7daff2e5270b5f3a4ddaa9a50ce8a2db18 --- /dev/null +++ b/carrera/fptrap.c @@ -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; +} diff --git a/carrera/io.h b/carrera/io.h new file mode 100644 index 0000000000000000000000000000000000000000..82e29d92270b303f646d6b84249558ae614dd80e --- /dev/null +++ b/carrera/io.h @@ -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, +}; diff --git a/carrera/l.s b/carrera/l.s new file mode 100644 index 0000000000000000000000000000000000000000..a106d2be30b6f43d25981c5fbad033d3a020596c --- /dev/null +++ b/carrera/l.s @@ -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 diff --git a/carrera/main.c b/carrera/main.c new file mode 100644 index 0000000000000000000000000000000000000000..f6bc43dac17abf121b971719d6ad0287dac505e7 --- /dev/null +++ b/carrera/main.c @@ -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; +} + diff --git a/carrera/mem.h b/carrera/mem.h new file mode 100644 index 0000000000000000000000000000000000000000..be1c5adb1deca8c708d38f2fa16296df5dd7c5f0 --- /dev/null +++ b/carrera/mem.h @@ -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)&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<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)<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; ipidonmach[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; inewtlb = 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; +} diff --git a/carrera/segment.h b/carrera/segment.h new file mode 100644 index 0000000000000000000000000000000000000000..a98428adac9a6cacf1c1dc58cd811c9f4dc6710e --- /dev/null +++ b/carrera/segment.h @@ -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 }, +}; diff --git a/carrera/trap.c b/carrera/trap.c new file mode 100644 index 0000000000000000000000000000000000000000..70eed48939cc2d92f93751508fe3d591d002d35d --- /dev/null +++ b/carrera/trap.c @@ -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<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; iprocctl) + 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; +} diff --git a/port/segment.c b/port/segment.c index d39ae9735558fb7fb03cce1256986bfebb227178..21e1a9449fcb1aa53cbead6fb38e7d59132c9bf6 100644 --- a/port/segment.c +++ b/port/segment.c @@ -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;