diff -Nru /sys/src/9/vt5/archvt5.c /sys/src/9/vt5/archvt5.c --- /sys/src/9/vt5/archvt5.c Thu Jan 1 00:00:00 1970 +++ /sys/src/9/vt5/archvt5.c Fri Jun 7 00:00:00 2013 @@ -0,0 +1,321 @@ +/* + * rae's virtex5 ml510 ppc440x5 + * similar to the ml410 but only 4 leds, not 8. + */ + +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" + +#include "io.h" +#include "../port/netif.h" +#include "etherif.h" +#include "../ip/ip.h" + +#include "reboot.h" + +enum { + Ledmask = (1<<4) - 1, /* for 4 bits */ +}; + +typedef struct Gpioregs Gpioregs; + +struct Gpioregs { + ulong data; /* write only? */ + ulong tri; /* tri-state */ + ulong data2; /* 2nd channel */ + ulong tri2; + + /* silly bits */ + ulong pad[67]; /* sheesh */ + ulong gie; /* global intr enable */ + ulong ier; /* intr enable */ + ulong isr; /* intr status */ +}; + +void machninit(int); + +static void twinkle(void); + +void (*archclocktick)(void) = twinkle; +/* ether= for sys=anguish */ +uchar mymac[Eaddrlen] = { 0x00, 0x0A, 0x35, 0x01, 0xE1, 0x48 }; +uintptr memsz; + +void +startcpu(int machno) +{ + machninit(machno); + mmuinit(); + /* + * can't print normally on cpu1 until we move shared locks + * into uncached sram and change synchronisation between + * the cpus fairly drastically. cpu1 will then be a slave. + */ +uartlputc('Z'); +uartlputc('Z'); +uartlputc('0'+machno); + splhi(); + for(;;) { + putmsr(getmsr() | MSR_WE); + barriers(); + } +} + +void +uncinit(void) +{ +} + +void +archreset(void) +{ + m->cpuhz = 400000000; + m->opbhz = 66600000; + m->clockgen = m->cpuhz; /* it's the internal cpu clock */ +} + +void +archvt5link(void) +{ +} + +int +cmpswap(long *addr, long old, long new) +{ + return cas32(addr, old, new); +} + +/* + * only use of GPIO now is access to LEDs + */ + +//static int leds; +static uchar oldbits; +static Lock lightlck; + +static void +setleds(void) +{ + ((Gpioregs*)Gpio)->data = ~oldbits & Ledmask; /* 0 == lit */ + barriers(); +} + +static void +ledinit(void) +{ + Gpioregs *g; + + /* set access to LED */ + g = (Gpioregs*)Gpio; +/* g->gie = 0; /* wouldn't use intrs even if we had them */ + g->tri = 0; /* outputs */ + barriers(); + setleds(); +} + +uchar +lightstate(int state) +{ + int r; + + if (m->machno != 0) + return oldbits; + ilock(&lightlck); + r = oldbits; + oldbits &= ~(Ledtrap|Ledkern|Leduser|Ledidle); + oldbits |= state & (Ledtrap|Ledkern|Leduser|Ledidle); + iunlock(&lightlck); + setleds(); + return r; +} + +uchar +lightbiton(int bit) +{ + int r; + + if (m->machno != 0) + return oldbits; + ilock(&lightlck); + r = oldbits; + oldbits |= bit; + iunlock(&lightlck); + setleds(); + return r; +} + +uchar +lightbitoff(int bit) +{ + int r; + + if (m->machno != 0) + return oldbits; + ilock(&lightlck); + r = oldbits; + oldbits &= ~bit; + iunlock(&lightlck); + setleds(); + return r; +} + +static void +twinkle(void) +{ + static int bit; + + if (m->machno != 0) + return; + if(m->ticks % (HZ/4) == 0) { + bit ^= 1; + if (bit) + lightbiton(Ledpulse); + else + lightbitoff(Ledpulse); + barriers(); + } + + if(securemem) + qtmclock(); + if(m->ticks % HZ == 0) { + intrs1sec = 0; + etherclock(); + } + barriers(); +} + +/* + * size by watching for bus errors (machine checks), but avoid + * tlb faults for unmapped memory beyond the maximum we expect. + */ +static uintptr +memsize(void) +{ + int fault; + uintptr sz; + + /* try powers of two */ + fault = 0; + for (sz = MB; sz != 0 && sz < MAXMEM; sz <<= 1) + if (probeaddr(KZERO|sz) < 0) { + fault = 1; + break; + } + if (sz >= MAXMEM && !fault) + /* special handling for maximum size */ + if (probeaddr(KZERO|MEMTOP(sz)) < 0) + sz >>= 1; + + return securemem? MEMTOP(sz): sz; +} + +void +meminit(void) +{ + securemem = gotsecuremem(); + + /* size memory */ + memsz = memsize(); + conf.mem[0].npage = memsz / BY2PG; + conf.mem[0].base = PGROUND(PADDR(end)); + conf.mem[0].npage -= conf.mem[0].base/BY2PG; + + /* avoid clobbering bootstrap's stack in case cpu1 is using it */ +} + +void +ioinit(void) +{ + ledinit(); + addconf("console", "0"); + addconf("nobootprompt", "tcp"); +} + +int +archether(int ctlno, Ether *ether) +{ + if(ctlno > 0) + return -1; + + if (probeaddr(Temac) >= 0) { + ether->type = "lltemac"; + ether->port = ctlno; + return 1; + } + return -1; +} + +void +clrmchk(void) +{ + putmcsr(~0); /* clear machine check causes */ + sync(); + isync(); + putesr(0); /* clears machine check */ +} + +/* + * the new kernel is already loaded at address `code' + * of size `size' and (virtual) entry point `entry'. + */ +void +reboot(void *entry, void *code, ulong size) +{ + int cpu; + void (*f)(ulong, ulong, ulong); + + writeconf(); + shutdown(0); + + /* + * should be the only processor running now + */ + cpu = getpir(); + if (cpu != 0) + panic("rebooting on cpu %d", cpu); + + print("shutting down...\n"); + delay(200); + + splhi(); + + /* turn off buffered serial console */ +// serialoq = nil; + + /* shutdown devices */ + devtabshutdown(); + splhi(); /* device shutdowns could have lowered pl */ + intrshutdown(); + putmsr(getmsr() & ~MSR_DE); /* disable debug facilities */ + putdbsr(~0); + + /* setup reboot trampoline function */ + f = (void*)REBOOTADDR; + sync(); + memmove(f, rebootcode, sizeof(rebootcode)); + sync(); + dcflush(PTR2UINT(f), sizeof rebootcode); + icflush(PTR2UINT(f), sizeof rebootcode); + + iprint("restart: entry %#p code %#p size %ld; trampoline %#p", + entry, code, size, f); + delay(100); /* wait for uart to quiesce */ + + /* off we go - never to return */ + dcflush(PTR2UINT(entry), size); + icflush(PTR2UINT(entry), size); + /* + * trampoline code now at REBOOTADDR will copy code to entry, + * then jump to entry. + */ + iprint("\n"); + delay(10); + (*f)((uintptr)entry, (uintptr)code, size); + + /* never reached */ + iprint("new kernel returned!\n"); + archreboot(); +} diff -Nru /sys/src/9/vt5/clock.c /sys/src/9/vt5/clock.c --- /sys/src/9/vt5/clock.c Thu Jan 1 00:00:00 1970 +++ /sys/src/9/vt5/clock.c Fri Jun 7 00:00:00 2013 @@ -0,0 +1,130 @@ +/* ppc440 clock */ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" + +void +delay(int l) +{ + ulong i, j; + + j = m->delayloop; + while(l-- > 0) + for(i=0; i < j; i++) + ; +} + +void +microdelay(int l) +{ + ulong i; + + l *= m->delayloop; + l /= 1000; + if(l <= 0) + l = 1; + for(i = 0; i < l; i++) + ; +} + +enum { + Timebase = 1, /* system clock cycles per time base cycle */ + + Wp21= 0<<30, /* watchdog period (2^x clocks) */ + Wp25= 1<<30, + Wp29= 2<<30, + Wp33= 3<<30, + Wrnone= 0<<28, /* no watchdog reset */ + Wrcore= 1<<28, /* core reset */ + Wrchip= 2<<28, /* chip reset */ + Wrsys= 3<<28, /* system reset */ + Wie= 1<<27, /* watchdog interrupt enable */ + Pie= 1<<26, /* enable PIT interrupt */ + Fit13= 0<<24, /* fit period (2^x clocks) */ + Fit17= 1<<24, + Fit21= 2<<24, + Fit25= 3<<24, + Fie= 1<<23, /* fit interrupt enable */ + Are= 1<<22, /* auto reload enable */ + + /* dcr */ + Boot= 0x0F1, + Epctl= 0x0F3, + Pllmr0= 0x0F0, + Pllmr1= 0x0F4, + Ucr= 0x0F5, +}; + +void (*archclocktick)(void); /* set by arch*.c if used */ + +void +clockinit(void) +{ + long x; + + m->delayloop = m->cpuhz/1000; /* initial estimate */ + do { + x = gettbl(); + delay(10); + x = gettbl() - x; + } while(x < 0); + + /* + * fix count + */ + m->delayloop = ((vlong)m->delayloop * (10*(vlong)m->clockgen/1000)) / + (x*Timebase); + if((int)m->delayloop <= 0) + m->delayloop = 20000; + + x = (m->clockgen/Timebase)/HZ; + putpit(x); + puttsr(~0); + /* not sure if we want Wrnone or Wrcore */ +// puttcr(Pie|Are|Wie|Wrcore|Wp29); + puttcr(Pie|Are|Wrnone); +} + +void +clockintr(Ureg *ureg) +{ + /* PIT was set to reload automatically */ + puttsr(~0); + m->fastclock++; + timerintr(ureg, 0); + if(archclocktick != nil) + archclocktick(); +} + +uvlong +fastticks(uvlong *hz) +{ + if(hz) + *hz = HZ; + return m->fastclock; +} + +ulong +µs(void) +{ + return fastticks2us(m->fastclock); +} + +void +timerset(uvlong) +{ +} + +ulong +perfticks(void) +{ + return (ulong)fastticks(nil); +} + +long +lcycles(void) +{ + return perfticks(); +} diff -Nru /sys/src/9/vt5/dat.h /sys/src/9/vt5/dat.h --- /sys/src/9/vt5/dat.h Thu Jan 1 00:00:00 1970 +++ /sys/src/9/vt5/dat.h Fri Jun 7 00:00:00 2013 @@ -0,0 +1,302 @@ +typedef struct Conf Conf; +typedef struct Confmem Confmem; +typedef struct ISAConf ISAConf; +typedef struct Label Label; +typedef struct Lock Lock; +typedef struct Mach Mach; +typedef u32int Mreg; /* Msr - bloody UART */ +typedef struct Page Page; +typedef struct FPsave FPsave; +typedef struct PMMU PMMU; +typedef struct Notsave Notsave; +typedef struct Proc Proc; +typedef struct Softtlb Softtlb; +typedef struct Sys Sys; +typedef uvlong Tval; +typedef struct Ureg Ureg; + +#pragma incomplete Ureg + +#define MAXSYSARG 5 /* for mount(fd, mpt, flag, arg, srv) */ + +/* + * parameters for sysproc.c + */ +#define AOUT_MAGIC Q_MAGIC + +/* + * intc bits, as of 18 aug 2009. + * specific to rae's virtex5 design + */ +enum { + Bitllfifo, + Bittemac, + Bitdma, + Bitdma2, + Bituart, + Bitmiiphy, + Bitqtmmacfail, /* qtm only */ + Bitqtmdraminit, /* qtm only */ + + Intllfifo=1<pa|KZERO) +#define kmapinval() +#define kunmap(k) + +struct Mach +{ + /* OFFSETS OF THE FOLLOWING KNOWN BY l.s */ + int machno; /* physical id of processor [0*4] */ + ulong splpc; /* pc that called splhi() [1*4] */ + Proc *proc; /* current process on this processor [2*4] */ + Softtlb* stlb; /* software tlb cache [3*4] */ + int utlbhi; /* lowest tlb index in use by kernel [4*4] */ + int utlbnext; /* next tlb entry to use for user (round robin) [5*4] */ + int tlbfault; /* number of tlb i/d misses [6*4] */ + + /* ordering from here on irrelevant */ + + 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 inclockintr; + + Proc* readied; /* for runproc */ + ulong schedticks; /* next forced context switch */ + + Mach *me; /* debugging: should be my own address */ + + long oscclk; /* oscillator frequency (MHz) */ + long cpuhz; /* general system clock (cycles) */ + long clockgen; /* clock generator frequency (cycles) */ + long vcohz; + long pllhz; + long plbhz; + long opbhz; + long epbhz; + long pcihz; + int cputype; + ulong delayloop; + uvlong cyclefreq; /* frequency of user readable cycle clock */ + + Mach *me2; /* debugging: should be my own address */ + + uvlong fastclock; + Perf perf; /* performance counters */ + + int tlbpurge; /* ... */ + int pfault; + int cs; + int syscall; + int load; + int intr; + int flushmmu; /* make current proc flush its mmu state */ + int ilockdepth; + + int lastpid; /* last TLB pid allocated on this machine */ + QLock stlblock; /* prevent context switch during tlb update */ + Proc* pidproc[NTLBPID]; /* which proc owns a given pid */ + + ulong spuriousintr; + int lastintr; + + ulong magic; /* debugging; also check for stack overflow */ + + /* MUST BE LAST */ + int stack[1]; +}; + +struct Softtlb { + u32int hi; /* tlb hi, except that low order 10 bits have (pid[8]<<2) */ + u32int mid; + u32int lo; +}; + +struct +{ + Lock; + short machs; + short exiting; + short ispanic; + int thunderbirdsarego; /* lets the added processors continue to schedinit */ +}active; + +/* + * a parsed plan9.ini line + */ +#define NISAOPT 8 + +struct ISAConf { + char *type; + ulong port; + int irq; + ulong dma; + ulong mem; + ulong size; + ulong freq; + + int nopt; + char *opt[NISAOPT]; +}; + +#define MACHP(n) ((Mach *)((int)&mach0 + (n)*MACHSIZE)) +extern Mach mach0; + +extern register Mach *m; +extern register Proc *up; + +/* + * Horrid. But the alternative is 'defined'. + */ +#ifdef _DBGC_ +#define DBGFLG (dbgflg[_DBGC_]) +#else +#define DBGFLG (0) +#endif /* _DBGC_ */ + +// #define DBG(...) if(DBGFLG) dbgprint(__VA_ARGS__) + +typedef struct { + ulong lasttm; /* last mutation start in seconds */ + ulong startticks; + ulong lastticks; + ulong count; + ulong totticks; + + ulong period; /* in seconds */ +} Mutstats; +extern Mutstats mutstats; + +char dbgflg[256]; +ulong intrs1sec; /* count interrupts in this second */ +uintptr memsz; +int okprint; +int securemem; +int vflag; + +#define dbgprint print /* for now */ diff -Nru /sys/src/9/vt5/fns.h /sys/src/9/vt5/fns.h --- /sys/src/9/vt5/fns.h Thu Jan 1 00:00:00 1970 +++ /sys/src/9/vt5/fns.h Fri Jun 7 00:00:00 2013 @@ -0,0 +1,236 @@ +#define checkmmu(a, b) +#define countpagerefs(a, b) + +#include "../port/portfns.h" + +typedef struct Dma Dma; +typedef struct Ether Ether; +#pragma incomplete Dma + +void addconf(char*, char*); +int adec(long*); +int ainc(long*); +void archetherspeed(int, int); +void archinit(void); +uint archmiiport(int); +void archreboot(void); +void archreset(void); +ulong archuartclock(int, int); +void barriers(void); +uintptr cankaddr(uintptr pa); +Block* clallocb(void); +void clockinit(void); +void clockintr(Ureg*); +void clrmchk(void); +int cmpswap(long*, long, long); +#define coherence() mbar() +char *cputype2name(char *, int); +void cpuidprint(void); +void critintrvec(void); +#define cycles(ip) *(ip) = lcycles() +void dcbi(uintptr, usize); +void dcbst(uintptr, usize); +void dcflush(uintptr, usize); +void dcrcompile(void); +long decref(Ref*); +void delay(int); +void dtlbmiss(void); +void dump(void *, int); +void dumpmal(void); +void dumpregs(Ureg*); +void delayloopinit(void); +Dev* devtabget(int, int); +void devtabinit(void); +void devtabreset(void); +long devtabread(Chan*, void*, long, vlong); +void devtabshutdown(void); +void dump(void *, int); +void eieio(void); +void etherclock(void); +void evenaddr(uintptr); +void fifoinit(Ether *); +void firmware(int); +int fpipower(Ureg*); +int fpuavail(Ureg*); +int fpudevprocio(Proc*, void*, long, uintptr, int); +int fpuemu(Ureg*); +void fpuinit(void); +void fpunoted(void); +void fpunotify(Ureg*); +void fpuprocresetore(Proc*); +#define fpuprocresetore(p) USED(p) +void fpuprocsave(Proc*); +#define fpuprocsave(p) USED(p) +void fpusysprocsetup(Proc*); +void fpusysrfork(Ureg*); +void fpusysrforkchild(Proc*, Ureg*, Proc*); +void fputrap(Ureg*, int); +char* getconf(char*); +u32int getccr0(void); +u32int getdar(void); +u32int getdcr(int); +u32int getdear(void); +u32int getdec(void); +u32int getesr(void); +u32int getmcsr(void); +u32int getmsr(void); +u32int getpid(void); +u32int getpir(void); +u32int getpit(void); +u32int getpvr(void); +u32int getstid(void); +u32int gettbl(void); +u32int gettsr(void); +void gotopc(uintptr); +int gotsecuremem(void); +int havetimer(void); +void iccci(void); +void icflush(uintptr, usize); +void idlehands(void); +int inb(int); +long incref(Ref*); +void insb(int, void*, int); +ushort ins(int); +void inss(int, void*, int); +ulong inl(int); +void insl(int, void*, int); +void intr(Ureg*); +void intrdisable(int, void (*)(Ureg*, void*), void*, int, char*); +void intrfmtcounts(char *s, char *se); +void intrinit(void); +void intrshutdown(void); +int ioalloc(int, int, int, char*); +void iofree(int); +void ioinit(void); +int iprint(char*, ...); +void isync(void); +void itlbmiss(void); +void kexit(Ureg*); +void* kmapphys(uintptr, uintptr, ulong, ulong, ulong); +uchar lightbitoff(int); +uchar lightbiton(int); +uchar lightstate(int); +void links(void); +void malinit(void); +void mbar(void); +void meminit(void); +void mmuinit(void); +void* mmucacheinhib(void*, ulong); +ulong mmumapsize(ulong); +void mutateproc(void *); +int mutatetrigger(void); +int newmmupid(void); +int notify(Ureg*); +void outb(int, int); +void outsb(int, void*, int); +void outs(int, ushort); +void outss(int, void*, int); +void outl(int, ulong); +void outsl(int, void*, int); +u32int pidget(void); +void pidput(u32int); +vlong pokeaddr(uintptr addr, uint, uint); +void ppc405console(void); +vlong probeaddr(uintptr addr); +#define procrestore(p) +void procsave(Proc*); +void procsetup(Proc*); +void putdbsr(ulong); +void putdcr(int, u32int); +void putdec(ulong); +void putesr(ulong); +void putevpr(ulong); +void putmcsr(u32int); +void putmsr(u32int); +void putpid(u32int); +void putpit(u32int); +void putsdr1(u32int); +void puttcr(u32int); +void puttsr(u32int); +ulong qtmborder(void); +void qtmclock(void); +void qtmerr(void); +void qtmerrs(char *); +void qtminit(void); +void shutdown(int ispanic); +void spldone(void); +int splhi(void); +int spllo(void); +void splx(int); +void splxpc(int); +void startcpu(int); +u32int stidget(void); +u32int stidput(u32int); +void sync(void); +void syscall(Ureg*); +uintptr sysexecstack(uintptr, int); +void sysprocsetup(Proc*); +#define tas tas32 +void temactransmit(Ether *); +void touser(uintptr); +void trapinit(void); +void trapcritvec(void); +void trapvec(void); +void trapmvec(void); +void tlbdump(char *s); +u32int tlbrehi(int); +u32int tlbrelo(int); +u32int tlbremd(int); +int tlbsxcc(uintptr); +void tlbwrx(int, u32int, u32int, u32int); +void uartliteconsole(void); +void uartlputc(int); +void uartlputs(char *s); +void uncinit(void); +void uncinitwait(void); +#define userureg(ur) (((ur)->status & MSR_PR) != 0) +void verifyproc(Proc *); +void verifymach(Mach *); +#define waserror() (up->nerrlab++, setlabel(&up->errlab[up->nerrlab-1])) +void watchreset(void); +void whackether(Ether *); +void writeconf(void); + +/* + * dma.c + */ +void dma0init(void); +void dmainit(void); +int dmastart(int, void *dest, void *src, ulong len, ulong flags, void (*f)(int)); +void dmawait(int); + +/* + * intr.c + */ +void intrack(ulong); +void intrenable(ulong bit, int (*func)(ulong), char *); +void intrinit(void); + +int cas32(void*, u32int, u32int); +int tas32(void*); + +#define CASU(p, e, n) cas32((p), (u32int)(e), (u32int)(n)) +#define CASV(p, e, n) cas32((p), (u32int)(e), (u32int)(n)) +#define CASW(addr, exp, new) cas32((addr), (exp), (new)) +#define TAS(addr) tas32(addr) + +void forkret(void); + +#define PTR2UINT(p) ((uintptr)(p)) +#define UINT2PTR(i) ((void*)(i)) + +#define isphys(a) (((ulong)(a)&KSEGM)!=KSEG0 && ((ulong)(a)&KSEGM)!=KSEG1) +#define KADDR(a) ((void*)((ulong)(a) | KZERO)) +#define PADDR(a) (isphys(a)? (ulong)(a): ((ulong)(a) & ~KSEGM)) + +/* + * this low-level printing stuff is ugly, + * but there appears to be no other way to + * print until after #t is populated. + */ + +#define wave(c) { \ + barriers(); \ + *(ulong *)Uartlite = (c); \ + barriers(); \ +} diff -Nru /sys/src/9/vt5/l.s /sys/src/9/vt5/l.s --- /sys/src/9/vt5/l.s Thu Jan 1 00:00:00 1970 +++ /sys/src/9/vt5/l.s Fri Jun 7 00:00:00 2013 @@ -0,0 +1,1216 @@ +/* virtex5 ppc440x5 machine assist */ + +#include "mem.h" + +#define CPU0ONLY /* if defined, put cpu1 to sleep for now */ + + +/* + * Special Purpose Registers of interest here (440 versions) + */ +#define SPR_CCR0 0x3b3 /* Core Configuration Register 0 */ +#define SPR_CCR1 0x378 /* core configuration register 1 */ +#define SPR_DAC1 0x13c /* Data Address Compare 1 */ +#define SPR_DAC2 0x13d /* Data Address Compare 2 */ +#define SPR_DBCR0 0x134 /* Debug Control Register 0 */ +#define SPR_DBCR1 0x135 /* Debug Control Register 1 */ +#define SPR_DBCR2 0x136 /* Debug Control Register 1 */ +#define SPR_DBSR 0x130 /* Debug Status Register */ +#define SPR_DVC1 0x13e /* Data Value Compare 1 */ +#define SPR_DVC2 0x13f /* Data Value Compare 2 */ +#define SPR_DEAR 0x3D /* Data Error Address Register */ +#define SPR_ESR 0x3E /* Exception Syndrome Register */ +#define SPR_IAC1 0x138 /* Instruction Address Compare 1 */ +#define SPR_IAC2 0x139 /* Instruction Address Compare 2 */ +#define SPR_IAC3 0x13a /* Instruction Address Compare 3 */ +#define SPR_IAC4 0x13b /* Instruction Address Compare 4 */ +#define SPR_PID 0x30 /* Process ID (not the same as 405) */ +#define SPR_PVR 0x11f /* Processor Version Register */ + +#define SPR_SPRG0 0x110 /* SPR General 0 */ +#define SPR_SPRG1 0x111 /* SPR General 1 */ +#define SPR_SPRG2 0x112 /* SPR General 2 */ +#define SPR_SPRG3 0x113 /* SPR General 3 */ + +/* beware that these registers differ in R/W ability on 440 compared to 405 */ +#define SPR_SPRG4R 0x104 /* SPR general 4; user/supervisor R */ +#define SPR_SPRG5R 0x105 /* SPR general 5; user/supervisor R */ +#define SPR_SPRG6R 0x106 /* SPR general 6; user/supervisor R */ +#define SPR_SPRG7R 0x107 /* SPR general 7; user/supervisor R */ +#define SPR_SPRG4W 0x114 /* SPR General 4; supervisor W */ +#define SPR_SPRG5W 0x115 /* SPR General 5; supervisor W */ +#define SPR_SPRG6W 0x116 /* SPR General 6; supervisor W */ +#define SPR_SPRG7W 0x117 /* SPR General 7; supervisor W */ + +#define SPR_SRR0 0x01a /* Save/Restore Register 0 */ +#define SPR_SRR1 0x01b /* Save/Restore Register 1 */ +#define SPR_CSRR0 0x03a /* Critical Save/Restore Register 0 */ +#define SPR_CSRR1 0x03b /* Critical Save/Restore Register 1 */ +#define SPR_TBL 0x11c /* Time Base Lower */ +#define SPR_TBU 0x11d /* Time Base Upper */ +#define SPR_PIR 0x11e /* Processor Identity Register */ + +#define SPR_TCR 0x154 /* timer control */ +#define SPR_TSR 0x150 /* timer status */ +#define SPR_MMUCR 0x3B2 /* mmu control */ +#define SPR_DNV0 0x390 /* data cache normal victim 0-3 */ +#define SPR_DNV1 0x391 +#define SPR_DNV2 0x392 +#define SPR_DNV3 0x393 +#define SPR_DTV0 0x394 /* data cache transient victim 0-3 */ +#define SPR_DTV1 0x395 +#define SPR_DTV2 0x396 +#define SPR_DTV3 0x397 +#define SPR_DVLIM 0x398 /* data cache victim limit */ +#define SPR_INV0 0x370 /* instruction cache normal victim 0-3 */ +#define SPR_INV1 0x371 +#define SPR_INV2 0x372 +#define SPR_INV3 0x374 +#define SPR_ITV0 0x374 /* instruction cache transient victim 0-3 */ +#define SPR_ITV1 0x375 +#define SPR_ITV2 0x376 +#define SPR_ITV3 0x377 +#define SPR_IVOR(n) (0x190+(n)) /* interrupt vector offset registers 0-15 */ +#define SPR_IVPR 0x03F /* instruction vector prefix register */ +#define SPR_IVLIM 0x399 /* instruction cache victim limit */ + +#define SPR_MCSRR0 0x23A /* 440GX only */ +#define SPR_MCSRR1 0x23B +#define SPR_MCSR 0x23C + +#define SPR_DEC 0x16 /* on 440 they've gone back to using DEC instead of PIT ... */ +#define SPR_DECAR 0x36 /* ... with the auto-reload register now visible */ + +/* 440 */ + +/* use of SPRG registers in save/restore */ +#define SAVER0 SPR_SPRG0 +#define SAVER1 SPR_SPRG1 +#define SAVELR SPR_SPRG2 +#define SAVEXX SPR_SPRG3 + +/* special instruction definitions */ +#define BDNZ BC 16,0, +#define BDNE BC 0,2, + +#define TBRL 268 /* read time base lower in MFTB */ +#define TBRU 269 /* read time base upper in MFTB */ +#define MFTB(tbr,d) WORD $((31<<26)|((d)<<21)|((tbr&0x1f)<<16)|(((tbr>>5)&0x1f)<<11)|(371<<1)) + +#define TLBIA WORD $((31<<26)|(370<<1)) +#define TLBSYNC WORD $((31<<26)|(566<<1)) + +/* 400 models; perhaps others */ +#define ICCCI(a,b) WORD $((31<<26)|((a)<<16)|((b)<<11)|(966<<1)) +#define DCCCI(a,b) WORD $((31<<26)|((a)<<16)|((b)<<11)|(454<<1)) +/* these follow the source -> dest ordering */ +#define DCREAD(s,t) WORD $((31<<26)|((t)<<21)|((s)<<11)|(486<<1)) +#define DCRF(n) ((((n)>>5)&0x1F)|(((n)&0x1F)<<5)) +#define MTDCR(s,n) WORD $((31<<26)|((s)<<21)|(DCRF(n)<<11)|(451<<1)) +#define MFDCR(n,t) WORD $((31<<26)|((t)<<21)|(DCRF(n)<<11)|(323<<1)) +#define MSYNC WORD $((31<<26)|(598<<1)) +#define TLBRELO(a,t) WORD $((31<<26)|((t)<<21)|((a)<<16)|(2<<11)|(946<<1)) +#define TLBREMD(a,t) WORD $((31<<26)|((t)<<21)|((a)<<16)|(1<<11)|(946<<1)) +#define TLBREHI(a,t) WORD $((31<<26)|((t)<<21)|((a)<<16)|(0<<11)|(946<<1)) +#define TLBWELO(s,a) WORD $((31<<26)|((s)<<21)|((a)<<16)|(2<<11)|(978<<1)) +#define TLBWEMD(s,a) WORD $((31<<26)|((s)<<21)|((a)<<16)|(1<<11)|(978<<1)) +#define TLBWEHI(s,a) WORD $((31<<26)|((s)<<21)|((a)<<16)|(0<<11)|(978<<1)) +#define TLBSXF(a,b,t) WORD $((31<<26)|((t)<<21)|((a)<<16)|((b)<<11)|(914<<1)) +#define TLBSXCC(a,b,t) WORD $((31<<26)|((t)<<21)|((a)<<16)|((b)<<11)|(914<<1)|1) +/* + * these are useless because there aren't CE/CEI equivalents for + * critical interrupts, which are caused by critical input, debug exceptions + * or watchdog time-outs. + */ +//#define WRTMSR_EE(s) WORD $((31<<26)|((s)<<21)|(131<<1)) +//#define WRTMSR_EEI(e) WORD $((31<<26)|((e)<<15)|(163<<1)) + +/* + * there are three flavours of barrier: MBAR, MSYNC and ISYNC. + * ISYNC is a context sync, a strong instruction barrier. + * MSYNC is an execution sync (weak instruction barrier) + data storage barrier. + * MBAR is a memory (data storage) barrier. + */ +#define MBAR EIEIO + +/* + * on some models mtmsr doesn't synchronise enough (eg, 603e). + * the 440 does, however. + */ +#define MSRSYNC /* MSYNC; ISYNC */ + +/* on the 405 series, the prefetcher madly fetches across RFI, sys call, and others; use BR 0(PC) to stop */ +#define RFI WORD $((19<<26)|(50<<1)); BR 0(PC) +#define RFCI WORD $((19<<26)|(51<<1)); BR 0(PC) + +#define STEP(c) MSYNC; MOVW $(Uartlite+4), R7; MOVW c, R8; MOVW R8, 0(R7); MSYNC + +/* + * print progress character iff on cpu0. + * steps on R7 and R8, needs SB set and TLB entry for i/o registers set. + */ +#define STEP0(c, zero, notzero) \ + MOVW SPR(SPR_PIR), R7; \ + CMP R7, $0; \ + BEQ zero; \ + CMP R7, $017; \ + BNE notzero; \ +zero: STEP(c); \ +notzero: MSYNC + +#define UREGSPACE (UREGSIZE+8) + + NOSCHED + + TEXT start(SB), 1, $-4 + /* + * utterly clobber any outstanding machine checks before anything else + */ + MOVW $0, R0 + MSRSYNC + MOVW MSR, R3 + RLWNM $0, R3, $~MSR_ME, R3 /* disable machine check traps */ + ISYNC + MOVW R3, MSR + MSRSYNC + MOVW $-1, R3 + MOVW R3, SPR(SPR_MCSR) /* clear machine check causes */ + MSRSYNC + MOVW R0, SPR(SPR_ESR) /* clears machine check */ + MSRSYNC + MSYNC /* instead of above MSRSYNC */ + + /* + * setup MSR + * turn off interrupts, FPU + * use 0x000 as exception prefix + * enable machine check + */ + MOVW MSR, R3 + RLWNM $0, R3, $~MSR_EE, R3 + RLWNM $0, R3, $~MSR_CE, R3 + RLWNM $0, R3, $~MSR_FP, R3 + RLWNM $0, R3, $~(MSR_IS|MSR_DS), R3 + OR $(MSR_ME|MSR_DE), R3 + ISYNC + MOVW R3, MSR + MSRSYNC + + /* except during trap handling, R0 is zero from now on */ + MOVW $0, R0 + MOVW R0, CR + + /* we may be running at 0 or KZERO */ + /* setup SB for pre mmu */ + BL 1(PC) + MOVW LR, R9 + MOVW R9, R10 + ANDCC $KZERO, R10 /* R10 gets 0 or KZERO */ + MOVW $setSB-KZERO(SB), R2 /* SB until tlb established */ + OR R10, R2 /* adapt to address space */ + + MOVW $18, R18 + MOVW $19, R19 + MOVW $20, R20 + MOVW $21, R21 + MOVW $22, R22 + MOVW $23, R23 + MOVW $24, R24 + +STEP0($'\n', zeronl, notzeronl) +STEP0($'P', zeroP, notzeroP) + +/* + * invalidate the caches + */ + ICCCI(0, 2) /* this flushes the icache of a 440; the errata reveals that EA is used; we'll use SB */ + ISYNC + DCCCI(0, 2) /* this flash invalidates the dcache of a 440 (must not be in use) */ + MSRSYNC + + MOVW R0, SPR(SPR_DBCR0) + MOVW R0, SPR(SPR_DBCR1) + MOVW R0, SPR(SPR_DBCR2) + ISYNC + MOVW $~0, R3 + MOVW R3, SPR(SPR_DBSR) + +STEP0($'l', zerol, notzerol) + + /* + * CCR0: + * recover from data parity = 1 + * disable gathering = 0 + * disable trace broadcast = 1 + * disable apu instruction broadcast = 1 + * force load/store alignment = 1 + * apu/fpu use = 0 + * fill one speculative line on icache miss (errata #38, #40) = 0 + * CCR1: + * normal parity, normal cache operation + * cpu timer advances with tick of CPU input clock + * (not timer clock) TCS=0 + */ + MOVW $((1<<30)|(0<<21)|(1<<20)|(1<<15)|(1<<8)|(0<<5)|(0<<2)), R3 + MOVW R3, SPR(SPR_CCR0) + MOVW $(0<<7), R3 /* TCS=0; 1<<11 is full-line flush */ + MOVW R3, SPR(SPR_CCR1) + + /* clear i/d cache regions */ + MOVW R0, SPR(SPR_INV0) + MOVW R0, SPR(SPR_INV1) + MOVW R0, SPR(SPR_INV2) + MOVW R0, SPR(SPR_INV3) + MOVW R0, SPR(SPR_DNV0) + MOVW R0, SPR(SPR_DNV1) + MOVW R0, SPR(SPR_DNV2) + MOVW R0, SPR(SPR_DNV3) + + /* set i/d cache limits (all normal) */ + MOVW $((0<<22)|(63<<11)|(0<<0)), R3 /* TFLOOR=0, TCEILING=63 ways, NFLOOR = 0 */ + MOVW R3, SPR(SPR_DVLIM) + MOVW R3, SPR(SPR_IVLIM) + + /* + * set other system configuration values + */ + MOVW R0, SPR(SPR_DEC) + MOVW $~0, R3 + MOVW R3, SPR(SPR_TSR) + MOVW R0, SPR(SPR_TCR) + +#ifdef CPU0ONLY + /* put cpus other than first to sleep */ + MOVW SPR(SPR_PIR), R3 + CMP R3, R0 + BEQ okcpu + CMP R3, $017 + BEQ okcpu +STEP($'Z') +STEP($'Z') + ADD $'0', R3 +STEP(R3) +sleep: + MOVW MSR, R3 + RLWNM $0, R3, $~MSR_EE, R3 + RLWNM $0, R3, $~MSR_CE, R3 + OR $MSR_WE, R3 + ISYNC + MOVW R3, MSR + MSRSYNC + BR sleep +okcpu: +#endif + + MOVW $KZERO, R3 + CMPU R9, R3 + BGT highaddr + MOVW $'L', R11 /* R11 gets 'L' or 'H' */ + BR done +highaddr: + MOVW $'H', R11 +done: + +STEP0($'a', zeroa, notzeroa) + BL kernelmmu(SB) + + /* + * now running with MMU on, in kernel address space (at KZERO). + */ + +STEP0($'n', zeron, notzeron) + /* set SB to match new address space */ + MOVW $setSB(SB), R2 + +STEP0($' ', zerosp, notzerosp) + /* make the vectors match the old values */ + MOVW $(KZERO | VECBASE), R3 + MOVW R3, SPR(SPR_IVPR) /* vector prefix at KZERO */ + MOVW $INT_CI, R3 + MOVW R3, SPR(SPR_IVOR(0)) + MOVW $INT_MCHECK, R3 + MOVW R3, SPR(SPR_IVOR(1)) + MOVW $INT_DSI, R3 + MOVW R3, SPR(SPR_IVOR(2)) + MOVW $INT_ISI, R3 + MOVW R3, SPR(SPR_IVOR(3)) + MOVW $INT_EI, R3 + MOVW R3, SPR(SPR_IVOR(4)) + MOVW $INT_ALIGN, R3 + MOVW R3, SPR(SPR_IVOR(5)) + MOVW $INT_PROG, R3 + MOVW R3, SPR(SPR_IVOR(6)) + MOVW $INT_FPU, R3 + MOVW R3, SPR(SPR_IVOR(7)) /* reserved (FPU?) */ + MOVW $INT_SYSCALL, R3 + MOVW R3, SPR(SPR_IVOR(8)) /* system call */ + MOVW $INT_APU, R3 + MOVW R3, SPR(SPR_IVOR(9)) /* aux. proc. unavail. */ + MOVW $INT_PIT, R3 + MOVW R3, SPR(SPR_IVOR(10)) /* decrementer */ + MOVW $INT_FIT, R3 + MOVW R3, SPR(SPR_IVOR(11)) /* fixed interval */ + MOVW $INT_WDT, R3 + MOVW R3, SPR(SPR_IVOR(12)) /* watchdog */ + MOVW $INT_DMISS, R3 + MOVW R3, SPR(SPR_IVOR(13)) /* data TLB */ + MOVW $INT_IMISS, R3 + MOVW R3, SPR(SPR_IVOR(14)) /* instruction TLB */ + MOVW $INT_DEBUG, R3 + MOVW R3, SPR(SPR_IVOR(15)) /* debug */ + + ISYNC + /* invalidate the caches again to flush any addresses below KZERO */ + ICCCI(0, 2) /* this flushes the icache of a 440; the errata reveals that EA is used; we'll use SB */ + ISYNC + +/* BL kfpinit(SB) */ + +STEP0($'9', zero9, notzero9) + /* set up Mach */ + MOVW $mach0(SB), R(MACH) + MOVW SPR(SPR_PIR), R3 + CMP R3, R0 + BEQ bootcpub + CMP R3, $017 + BEQ bootcpub + ADD $MACHSIZE, R(MACH) /* use second Mach struct on cpu1 */ +bootcpub: + ADD $(MACHSIZE-8), R(MACH), R1 /* set stack */ + SUB $4, R(MACH), R3 + ADD $4, R1, R4 +// STEP0($'z', zero90, notzero90) +clrmach: + MOVWU R0, 4(R3) + CMP R3, R4 + BNE clrmach + + MOVW R0, R(USER) + MOVW R0, 0(R(MACH)) + + MSRSYNC + MSYNC /* instead of above MSRSYNC */ + +STEP0($' ', zerosp2, notzerosp2) + MOVW SPR(SPR_PIR), R3 + CMP R3, R0 + BEQ bootcpu + CMP R3, $017 + BNE appcpu +bootcpu: + /* only clear bss on cpu0 */ + MOVW $edata(SB), R3 + MOVW $end(SB), R4 + ADD $4, R4 + SUB $4, R3 +clrbss: + MOVWU R0, 4(R3) + CMP R3, R4 + BNE clrbss + +appcpu: + MSYNC + + /* print H or L */ +STEP0(R11, zerodig, notzerodig) +STEP0($'\r', zerocr, notzerocr) +STEP0($'\n', zeronl2, notzeronl2) + + MOVW $((200*1000*1000)/300), R1 /* 3 or 4 ms */ +delay: + SUB $1, R1 + CMP R1, R0 + BNE delay + + BL main(SB) + BR 0(PC) /* paranoia -- not reached */ + + +/* R10 is or-ed into addresses of tlbtab & tlbtabe */ +TEXT kernelmmu(SB), 1, $-4 + /* make following TLB entries shared, TID=PID=0 */ + MOVW R0, SPR(SPR_PID) + + /* + * allocate cache on store miss, disable U1 as transient, + * disable U2 as SWOA, no dcbf or icbi exception, tlbsx search 0. + */ + MOVW R0, SPR(SPR_MMUCR) + + /* map various things 1:1 */ + MOVW $tlbtab-KZERO(SB), R4 + OR R10, R4 /* adapt to address space */ + MOVW $tlbtabe-KZERO(SB), R5 + OR R10, R5 /* adapt to address space */ + SUB R4, R5 + MOVW $(3*4), R6 + DIVW R6, R5 + SUB $4, R4 + MOVW R5, CTR + MOVW $63, R3 +ltlb: + MOVWU 4(R4), R5 /* TLBHI */ + TLBWEHI(5,3) + MOVWU 4(R4), R5 /* TLBMD */ + TLBWEMD(5,3) + MOVWU 4(R4), R5 /* TLBLO */ + TLBWELO(5,3) + SUB $1, R3 + BDNZ ltlb + + /* clear all remaining entries to remove any aliasing from boot */ + CMP R3, R0 + BEQ cltlbe +cltlb: + TLBWEHI(0,3) + TLBWEMD(0,3) + TLBWELO(0,3) + SUB $1, R3 + CMP R3, R0 + BGE cltlb +cltlbe: + + /* + * we're currently relying on the shadow I/D TLBs. to switch to + * the new TLBs, we need a synchronising instruction. ISYNC + * won't work here because the PC is still below KZERO, but + * there's no TLB entry to support that, and once we ISYNC the + * shadow i-tlb entry vanishes, taking the PC's location with it. + */ + MOVW LR, R4 + OR $KZERO, R4 + MOVW R4, SPR(SPR_SRR0) + MOVW MSR, R4 + MOVW R4, SPR(SPR_SRR1) + RFI /* resume in kernel mode in caller; R3 has the index of the first unneeded TLB entry */ + +TEXT tlbinval(SB), 1, $-4 + TLBWEHI(0, 3) + TLBWEMD(0, 3) + TLBWELO(0, 3) + ISYNC + RETURN + +TEXT splhi(SB), 1, $-4 + MOVW MSR, R3 + RLWNM $0, R3, $~MSR_EE, R4 + RLWNM $0, R4, $~MSR_CE, R4 + MOVW R4, MSR + MSRSYNC + MOVW LR, R31 + MOVW R31, 4(R(MACH)) /* save PC in m->splpc */ + RETURN + +/* + * everything from here up to, but excluding, spldone + * will be billed by devkprof to the pc saved when we went splhi. + */ +TEXT spllo(SB), 1, $-4 + MOVW MSR, R3 + OR $MSR_EE, R3, R4 + OR $MSR_CE, R4 + MOVW R4, MSR + MSRSYNC + RETURN + +TEXT splx(SB), 1, $-4 + MOVW LR, R31 + MOVW R31, 4(R(MACH)) /* save PC in m->splpc */ + /* fall though */ + +TEXT splxpc(SB), 1, $-4 + MOVW MSR, R4 + RLWMI $0, R3, $MSR_EE, R4 + RLWMI $0, R3, $MSR_CE, R4 + MOVW R4, MSR + MSRSYNC + RETURN + +/***/ +TEXT spldone(SB), 1, $-4 + RETURN + +TEXT islo(SB), 1, $-4 + MOVW MSR, R3 + MOVW $(MSR_EE|MSR_CE), R4 + AND R4, R3 + RETURN + +TEXT setlabel(SB), 1, $-4 + MOVW LR, R31 + MOVW R1, 0(R3) + MOVW R31, 4(R3) + MOVW $0, R3 + RETURN + +TEXT gotolabel(SB), 1, $-4 + MOVW 4(R3), R31 + MOVW R31, LR + MOVW 0(R3), R1 + MOVW $1, R3 + RETURN + +TEXT touser(SB), 1, $-4 + /* splhi */ + MOVW MSR, R5 + RLWNM $0, R5, $~MSR_EE, R5 + RLWNM $0, R5, $~MSR_CE, R5 + MOVW R5, MSR + MSRSYNC + MOVW R(USER), R4 /* up */ + MOVW 8(R4), R4 /* up->kstack */ + ADD $(KSTACK-UREGSPACE), R4 + MOVW R4, SPR(SPR_SPRG7W) /* save for use in traps/interrupts */ + MOVW $(UTZERO+32), R5 /* header appears in text */ + MOVW $UMSR, R4 + MOVW R4, SPR(SPR_SRR1) + MOVW R3, R1 + MOVW R5, SPR(SPR_SRR0) + ISYNC /* should be redundant with RFI */ + RFI + +/* invalidate i-cache */ +TEXT iccci(SB), 1, $-4 + ICCCI(0, 2) + MSYNC + RETURN + +/* invalidate i-cache region */ +TEXT icflush(SB), 1, $-4 /* icflush(virtaddr, count) */ + MSYNC + MOVW n+4(FP), R4 + RLWNM $0, R3, $~(ICACHELINESZ-1), R5 + SUB R5, R3 + ADD R3, R4 + ADD $(ICACHELINESZ-1), R4 + SRAW $ICACHELINELOG, R4 + MOVW R4, CTR +icf0: ICBI (R5) + ADD $ICACHELINESZ, R5 + BDNZ icf0 + ISYNC + RETURN + +/* write-back and invalidate d-cache region */ +TEXT dcflush(SB), 1, $-4 /* dcflush(virtaddr, count) */ + MSYNC + MOVW n+4(FP), R4 + RLWNM $0, R3, $~(DCACHELINESZ-1), R5 + CMP R4, $0 + BLE dcf1 + SUB R5, R3 + ADD R3, R4 + ADD $(DCACHELINESZ-1), R4 + SRAW $DCACHELINELOG, R4 + MOVW R4, CTR +dcf0: DCBF (R5) + ADD $DCACHELINESZ, R5 + BDNZ dcf0 +dcf1: + MSYNC + RETURN + +/* write-back d-cache region */ +TEXT dcbst(SB), 1, $-4 /* dcbst(virtaddr, count) */ + MSYNC + MOVW n+4(FP), R4 + RLWNM $0, R3, $~(DCACHELINESZ-1), R5 + CMP R4, $0 + BLE dcbst1 + SUB R5, R3 + ADD R3, R4 + ADD $(DCACHELINESZ-1), R4 + SRAW $DCACHELINELOG, R4 + MOVW R4, CTR +dcbst0: DCBST (R5) + ADD $DCACHELINESZ, R5 + BDNZ dcbst0 +dcbst1: + MSYNC + RETURN + +/* invalidate d-cache region */ +TEXT dcbi(SB), 1, $-4 /* dcbi(virtaddr, count) */ + MSYNC + MOVW n+4(FP), R4 + RLWNM $0, R3, $~(DCACHELINESZ-1), R5 + CMP R4, $0 + BLE dcbi1 + SUB R5, R3 + ADD R3, R4 + ADD $(DCACHELINESZ-1), R4 + SRAW $DCACHELINELOG, R4 + MOVW R4, CTR +dcbi0: DCBI (R5) + ADD $DCACHELINESZ, R5 + BDNZ dcbi0 +dcbi1: + MSYNC + RETURN + +TEXT tas32(SB), 1, $-4 + MOVW R3, R4 + MOVW $0xdead,R5 +tas1: + DCBF (R4) /* fix for 603x bug */ + LWAR (R4), R3 + CMP R3, $0 + BNE tas0 + STWCCC R5, (R4) + BNE tas1 +tas0: + RETURN + +TEXT _xinc(SB), 1, $-4 /* int _xinc(int*); */ +TEXT ainc(SB), 1, $-4 /* int ainc(int*); */ + MOVW R3, R4 +_ainc: + DCBF (R4) /* fix for 603x bug */ + LWAR (R4), R3 + ADD $1, R3 + STWCCC R3, (R4) + BNE _ainc + + CMP R3, $0 /* overflow if -ve or 0 */ + BGT _return +_trap: + MOVW $0, R0 + MOVW (R0), R0 /* over under sideways down */ +_return: + RETURN + +TEXT _xdec(SB), 1, $-4 /* int _xdec(int*); */ +TEXT adec(SB), 1, $-4 /* int adec(int*); */ + MOVW R3, R4 +_adec: + DCBF (R4) /* fix for 603x bug */ + LWAR (R4), R3 + ADD $-1, R3 + STWCCC R3, (R4) + BNE _adec + + CMP R3, $0 /* underflow if -ve */ + BLT _trap + RETURN + +TEXT cas32(SB), 1, $-4 /* int cas32(void*, u32int, u32int) */ + MOVW R3, R4 /* addr */ + MOVW old+4(FP), R5 + MOVW new+8(FP), R6 + DCBF (R4) /* fix for 603x bug? */ + LWAR (R4), R3 + CMP R3, R5 + BNE fail + STWCCC R6, (R4) + BNE fail + MOVW $1, R3 + RETURN +fail: + MOVW $0, R3 + RETURN + +TEXT getpit(SB), 1, $-4 + MOVW SPR(SPR_DEC), R3 /* they've moved it back to DEC */ + RETURN + +TEXT putpit(SB), 1, $-4 + MOVW R3, SPR(SPR_DEC) + MOVW R3, SPR(SPR_DECAR) + RETURN + +TEXT putpid(SB), 1, $-4 +TEXT pidput(SB), 1, $-4 + MOVW R3, SPR(SPR_PID) + MOVW SPR(SPR_MMUCR), R4 + RLWMI $0, R3, $0xFF, R4 + MOVW R4, SPR(SPR_MMUCR) + RETURN + +TEXT getpid(SB), 1, $-4 +TEXT pidget(SB), 1, $-4 + MOVW SPR(SPR_PID), R3 + RLWNM $0, R3, $0xFF, R3 + RETURN + +TEXT getpir(SB), 1, $-4 + MOVW SPR(SPR_PIR), R3 + CMP R3, $017 + BNE normal + MOVW R0, R3 +normal: + RETURN + +TEXT putstid(SB), 1, $-4 +TEXT stidput(SB), 1, $-4 + MOVW SPR(SPR_MMUCR), R4 + RLWMI $0, R3, $0xFF, R4 + MOVW R4, SPR(SPR_MMUCR) + RETURN + +TEXT getstid(SB), 1, $-4 +TEXT stidget(SB), 1, $-4 + MOVW SPR(SPR_MMUCR), R3 + RLWNM $0, R3, $0xFF, R3 + RETURN + +TEXT gettbl(SB), 1, $-4 + MFTB(TBRL, 3) + RETURN + +TEXT gettbu(SB), 1, $-4 + MFTB(TBRU, 3) + RETURN + +TEXT gettsr(SB), 1, $-4 + MOVW SPR(SPR_TSR), R3 + RETURN + +TEXT puttsr(SB), 1, $-4 + MOVW R3, SPR(SPR_TSR) + RETURN + +TEXT puttcr(SB), 1, $-4 + MOVW R3, SPR(SPR_TCR) + RETURN + +TEXT getpvr(SB), 1, $-4 + MOVW SPR(SPR_PVR), R3 + RETURN + +TEXT getmsr(SB), 1, $-4 + MOVW MSR, R3 + RETURN + +TEXT putmsr(SB), 1, $-4 + MOVW R3, MSR + MSRSYNC + RETURN + +TEXT getmcsr(SB), 1, $-4 + MOVW SPR(SPR_MCSR), R3 + RETURN + +TEXT putmcsr(SB), 1, $-4 + MOVW R3, SPR(SPR_MCSR) + RETURN + +TEXT getesr(SB), 1, $-4 + MOVW SPR(SPR_ESR), R3 + RETURN + +TEXT putesr(SB), 1, $-4 + MOVW R3, SPR(SPR_ESR) + RETURN + +TEXT putevpr(SB), 1, $-4 + MOVW R3, SPR(SPR_IVPR) + RETURN + +TEXT getccr0(SB), 1, $-4 + MOVW SPR(SPR_CCR0), R3 + RETURN + +TEXT getdear(SB), 1, $-4 + MOVW SPR(SPR_DEAR), R3 + RETURN + +TEXT getdcr(SB), 1, $-4 + MOVW $_getdcr(SB), R5 + SLW $3, R3 + ADD R3, R5 + MOVW R5, CTR + BR (CTR) + +TEXT putdcr(SB), 1, $-4 + MOVW $_putdcr(SB), R5 + SLW $3, R3 + ADD R3, R5 + MOVW R5, CTR + MOVW 8(R1), R3 + BR (CTR) + +TEXT putdbsr(SB), 1, $-4 + MOVW R3, SPR(SPR_DBSR) + RETURN + +TEXT barriers(SB), 1, $-4 +TEXT mbar(SB), 1, $-4 + MBAR + RETURN + +TEXT sync(SB), 1, $-4 + MSYNC + RETURN + +TEXT isync(SB), 1, $-4 + ISYNC + RETURN + +TEXT tlbwrx(SB), 1, $-4 + MOVW hi+4(FP), R5 + MOVW mid+8(FP), R6 + MOVW lo+12(FP), R7 + MSYNC + TLBWEHI(5, 3) + TLBWEMD(6, 3) + TLBWELO(7, 3) + ISYNC + RETURN + +TEXT tlbrehi(SB), 1, $-4 + TLBREHI(3, 3) + RETURN + +TEXT tlbremd(SB), 1, $-4 + TLBREMD(3, 3) + RETURN + +TEXT tlbrelo(SB), 1, $-4 + TLBRELO(3, 3) + RETURN + +TEXT tlbsxcc(SB), 1, $-4 + TLBSXCC(0, 3, 3) + BEQ tlbsxcc0 + MOVW $-1, R3 /* not found */ +tlbsxcc0: + RETURN + +TEXT gotopc(SB), 1, $0 + MOVW R3, CTR + MOVW LR, R31 /* for trace back */ + BR (CTR) + +TEXT dtlbmiss(SB), 1, $-4 + MOVW R0, SPR(SAVER0) + MOVW MSR, R0 + RLWNM $0, R0, $~MSR_CE, R0 + MOVW R0, MSR + MOVW SPR(SAVER0), R0 + + MOVW R3, SPR(SPR_SPRG1) + MOVW $INT_DMISS, R3 + MOVW R3, SPR(SAVEXX) /* value for cause if entry not in soft tlb */ + MOVW SPR(SPR_DEAR), R3 + BR tlbmiss + +TEXT itlbmiss(SB), 1, $-4 + MOVW R0, SPR(SAVER0) + MOVW MSR, R0 + RLWNM $0, R0, $~MSR_CE, R0 + MOVW R0, MSR + MOVW SPR(SAVER0), R0 + + MOVW R3, SPR(SPR_SPRG1) + MOVW $INT_IMISS, R3 + MOVW R3, SPR(SAVEXX) + MOVW SPR(SPR_SRR0), R3 + +tlbmiss: + /* R3 contains missed address */ + RLWNM $0, R3, $~(BY2PG-1), R3 /* just the page */ + MOVW R2, SPR(SPR_SPRG0) + MOVW R4, SPR(SPR_SPRG2) + MOVW R5, SPR(SPR_SPRG6W) + MOVW R6, SPR(SPR_SPRG4W) + MOVW CR, R6 + MOVW R6, SPR(SPR_SPRG5W) + MOVW $setSB(SB), R2 + MOVW $mach0(SB), R2 + MOVW (6*4)(R2), R4 /* m->tlbfault++ */ + ADD $1, R4 + MOVW R4, (6*4)(R2) + MOVW SPR(SPR_PID), R4 + SRW $12, R3, R6 + RLWMI $2, R4, $(0xFF<<2), R3 /* shift and insert PID for match */ + XOR R3, R6 /* hash=(va>>12)^(pid<<2); (assumes STLBSIZE is 10 to 12 bits) */ + MOVW (3*4)(R2), R5 /* m->stlb */ + RLWNM $0, R6, $(STLBSIZE-1), R6 /* mask */ + SLW $1, R6, R4 + ADD R4, R6 + SLW $2, R6 /* index 12-byte entries */ + MOVWU (R6+R5), R4 /* fetch Softtlb.hi for comparison; updated address goes to R5 */ + CMP R4, R3 + BNE tlbtrap + MFTB(TBRL, 6) + MOVW (4*4)(R2), R4 /* m->utlbhi */ + RLWNM $0, R6, $(NTLB-1), R6 /* pseudo-random tlb index */ + CMP R6, R4 + BLE tlbm1 + SUB R4, R6 +tlbm1: + RLWNM $0, R3, $~(BY2PG-1), R3 + OR $(TLB4K | TLBVALID), R3 /* make valid tlb hi */ + TLBWEHI(3, 6) + MOVW 4(R5), R4 /* tlb mid */ + TLBWEMD(4, 6) + MOVW 8(R5), R4 /* tlb lo */ + TLBWELO(4, 6) + ISYNC + MOVW SPR(SPR_SPRG5R), R6 + MOVW R6, CR + MOVW SPR(SPR_SPRG4R), R6 + MOVW SPR(SPR_SPRG6R), R5 + MOVW SPR(SPR_SPRG2), R4 + MOVW SPR(SPR_SPRG1), R3 + MOVW SPR(SPR_SPRG0), R2 + RFI + +tlbtrap: + MOVW SPR(SPR_SPRG5R), R6 + MOVW R6, CR + MOVW SPR(SPR_SPRG4R), R6 + MOVW SPR(SPR_SPRG6R), R5 + MOVW SPR(SPR_SPRG2), R4 + MOVW SPR(SPR_SPRG1), R3 + MOVW SPR(SPR_SPRG0), R2 + MOVW R0, SPR(SAVER0) + MOVW LR, R0 + MOVW R0, SPR(SAVELR) + BR trapcommon + +/* + * following Book E, traps thankfully leave the mmu on. + * the following code has been executed at the exception + * vector location already: + * MOVW R0, SPR(SAVER0) + * (critical interrupts disabled in MSR, using R0) + * MOVW LR, R0 + * MOVW R0, SPR(SAVELR) + * bl trapvec(SB) + */ +TEXT trapvec(SB), 1, $-4 + MOVW LR, R0 + MOVW R0, SPR(SAVEXX) /* save interrupt vector offset */ +trapcommon: /* entry point for machine checks, and full tlb faults */ + MOVW R1, SPR(SAVER1) /* save stack pointer */ + /* did we come from user space? */ + MOVW SPR(SPR_SRR1), R0 + MOVW CR, R1 + MOVW R0, CR + BC 4,17,ktrap /* if MSR[PR]=0, we are in kernel space */ + + /* was user mode, switch to kernel stack and context */ + MOVW R1, CR + + MOVW SPR(SPR_SPRG7R), R1 /* up->kstack+KSTACK-UREGSPACE, set in touser and forkret */ +// MFTB(TBRL, RTBL) /* time-stamp tracing in R28 */ + BL saveureg(SB) + MOVW $mach0(SB), R(MACH) + MOVW 8(R(MACH)), R(USER) + BL trap(SB) + BR restoreureg + +ktrap: + /* was kernel mode, R(MACH) and R(USER) already set */ + MOVW R1, CR + MOVW SPR(SAVER1), R1 + SUB $UREGSPACE, R1 /* push onto current kernel stack */ + BL saveureg(SB) + BL trap(SB) + +restoreureg: + MOVMW 48(R1), R2 /* r2:r31 */ + /* defer R1, R0 */ + MOVW 36(R1), R0 + MOVW R0, CTR + MOVW 32(R1), R0 + MOVW R0, XER + MOVW 28(R1), R0 + MOVW R0, CR /* CR */ + MOVW 24(R1), R0 + MOVW R0, LR + MOVW 20(R1), R0 + MOVW R0, SPR(SPR_SPRG7W) /* kstack for traps from user space */ + MOVW 16(R1), R0 + MOVW R0, SPR(SPR_SRR0) /* old PC */ + MOVW 12(R1), R0 + RLWNM $0, R0, $~MSR_WE, R0 /* remove wait state */ + MOVW R0, SPR(SPR_SRR1) /* old MSR */ + /* cause, skip */ + MOVW 40(R1), R0 + MOVW 44(R1), R1 /* old SP */ + RFI + +/* + * machine check. + * make it look like the others. + * it's safe to destroy SPR_SRR0/1 because they can only be in + * use if a critical interrupt has interrupted a non-critical interrupt + * before it has had a chance to block critical interrupts, + * but no recoverable machine checks can occur during a critical interrupt, + * so the lost state doesn't matter. + */ +TEXT trapmvec(SB), 1, $-4 + MOVW LR, R0 + MOVW R0, SPR(SAVEXX) + MOVW SPR(SPR_MCSRR0), R0 /* PC or excepting insn */ + MOVW R0, SPR(SPR_SRR0) + MOVW SPR(SPR_MCSRR1), R0 /* old MSR */ + MOVW R0, SPR(SPR_SRR1) + BR trapcommon + +/* + * external interrupts (non-critical) + */ +TEXT intrvec(SB), 1, $-4 + MOVW LR, R0 + MOVW R0, SPR(SAVEXX) /* save interrupt vector offset */ + MOVW R1, SPR(SAVER1) /* save stack pointer */ + + /* did we come from user space? */ + MOVW SPR(SPR_SRR1), R0 + MOVW CR, R1 + MOVW R0, CR + BC 4,17,intr1 /* if MSR[PR]=0, we are in kernel space */ + + /* was user mode, switch to kernel stack and context */ + MOVW R1, CR + MOVW SPR(SPR_SPRG7R), R1 /* up->kstack+KSTACK-UREGSPACE, set in touser and forkret */ + BL saveureg(SB) + MOVW $mach0(SB), R(MACH) + MOVW 8(R(MACH)), R(USER) + BL intr(SB) + BR restoreureg + +intr1: + /* was kernel mode, R(MACH) and R(USER) already set */ + MOVW R1, CR + MOVW SPR(SAVER1), R1 + SUB $UREGSPACE, R1 /* push onto current kernel stack */ + BL saveureg(SB) + BL intr(SB) + BR restoreureg + +/* + * critical interrupt + */ +TEXT critintrvec(SB), 1, $-4 + MOVW LR, R0 + MOVW R0, SPR(SAVEXX) + MOVW R1, SPR(SAVER1) /* save stack pointer */ + + /* did we come from user space? */ + MOVW SPR(SPR_CSRR1), R0 + MOVW CR, R1 + MOVW R0, CR + BC 4,16,kintrintr /* if MSR[EE]=0, kernel was interrupted at start of intrvec */ + BC 4,17,kcintr1 /* if MSR[PR]=0, we are in kernel space */ + +ucintr: + /* was user mode or intrvec interrupted: switch to kernel stack and context */ + MOVW R1, CR + MOVW SPR(SPR_SPRG7R), R1 /* up->kstack+KSTACK-UREGSPACE, set in touser and forkret */ + BL saveureg(SB) + MOVW $mach0(SB), R(MACH) + MOVW 8(R(MACH)), R(USER) + BR cintrcomm + +kintrintr: + /* kernel mode, and EE off, so kernel intrvec interrupted, but was previous mode kernel or user? */ + MOVW SPR(SPR_SRR1), R0 + MOVW R0, CR + BC (4+8),17,ucintr /* MSR[PR]=1, we were in user space, need set up */ + +kcintr1: + /* was kernel mode and external interrupts enabled, R(MACH) and R(USER) already set */ + MOVW R1, CR + MOVW SPR(SAVER1), R1 + SUB $UREGSPACE, R1 /* push onto current kernel stack */ + BL saveureg(SB) + +cintrcomm: + /* special part of Ureg for critical interrupts only (using Ureg.dcmp, Ureg.icmp, Ureg.dmiss) */ + MOVW SPR(SPR_SPRG6R), R4 /* critical interrupt saves volatile R0 in SPRG6 */ + MOVW R4, (160+8)(R1) + MOVW SPR(SPR_CSRR0), R4 /* store critical interrupt pc */ + MOVW R4, (164+8)(R1) + MOVW SPR(SPR_CSRR1), R4 /* critical interrupt msr */ + MOVW R4, (168+8)(R1) + + BL intr(SB) + + /* first restore usual part of Ureg */ + MOVMW 48(R1), R2 /* r2:r31 */ + /* defer R1, R0 */ + MOVW 40(R1), R0 + MOVW R0, SPR(SAVER0) /* restore normal r0 save */ + MOVW 36(R1), R0 + MOVW R0, CTR + MOVW 32(R1), R0 + MOVW R0, XER + MOVW 28(R1), R0 + MOVW R0, CR /* CR */ + MOVW 24(R1), R0 + MOVW R0, LR + MOVW 20(R1), R0 + MOVW R0, SPR(SPR_SPRG7W) /* kstack for traps from user space */ + MOVW 16(R1), R0 + MOVW R0, SPR(SPR_SRR0) /* saved normal PC */ + MOVW 12(R1), R0 + MOVW R0, SPR(SPR_SRR1) /* saved normal MSR */ + + /* restore special bits for critical interrupts */ + MOVW (164+8)(R1), R0 /* critical interrupt's saved pc */ + MOVW R0, SPR(SPR_CSRR0) + MOVW (168+8)(R1), R0 + RLWNM $0, R0, $~MSR_WE, R0 /* remove wait state */ + MOVW R0, SPR(SPR_CSRR1) + + /* cause, skip */ + MOVW (160+8)(R1), R0 /* critical interrupt's saved R0 */ + MOVW 44(R1), R1 /* old SP */ + RFCI + +/* + * enter with stack set and mapped. + * on return, SB (R2) has been set, and R3 has the Ureg*, + * the MMU has been re-enabled, kernel text and PC are in KSEG, + * Stack (R1), R(MACH) and R(USER) are set by caller, if required. + */ +TEXT saveureg(SB), 1, $-4 + MOVMW R2, 48(R1) /* save gprs r2 to r31 */ + MOVW $setSB(SB), R2 + MOVW SPR(SAVER1), R4 + MOVW R4, 44(R1) + MOVW SPR(SAVER0), R5 + MOVW R5, 40(R1) + MOVW CTR, R6 + MOVW R6, 36(R1) + MOVW XER, R4 + MOVW R4, 32(R1) + MOVW CR, R5 + MOVW R5, 28(R1) + MOVW SPR(SAVELR), R6 /* LR */ + MOVW R6, 24(R1) + MOVW SPR(SPR_SPRG7R), R6 /* up->kstack+KSTACK-UREGSPACE */ + MOVW R6, 20(R1) + MOVW SPR(SPR_SRR0), R0 + MOVW R0, 16(R1) /* PC of excepting insn (or next insn) */ + MOVW SPR(SPR_SRR1), R0 + MOVW R0, 12(R1) /* old MSR */ + MOVW SPR(SAVEXX), R0 + MOVW R0, 8(R1) /* cause/vector */ + ADD $8, R1, R3 /* Ureg* */ + STWCCC R3, (R1) /* break any pending reservations */ + MOVW $0, R0 /* compiler/linker expect R0 to be zero */ + RETURN + +/* + * restore state from Ureg and return from trap/interrupt + */ +TEXT forkret(SB), 1, $-4 + MOVW R1, 20(R1) /* up->kstack+KSTACK-UREGSPACE set in ureg */ + BR restoreureg + +/* + * 4xx specific + */ +TEXT firmware(SB), 1, $0 + ISYNC + MOVW $(3<<28), R3 + MOVW R3, SPR(SPR_DBCR0) /* system reset */ + ISYNC + BR 0(PC) + +GLOBL mach0(SB), $(MAXMACH*MACHSIZE) diff -Nru /sys/src/9/vt5/mem.h /sys/src/9/vt5/mem.h --- /sys/src/9/vt5/mem.h Thu Jan 1 00:00:00 1970 +++ /sys/src/9/vt5/mem.h Fri Jun 7 00:00:00 2013 @@ -0,0 +1,220 @@ +/* + * Memory and machine-specific definitions. Used in C and assembler. + */ +#define KiB 1024u /* Kibi 0x0000000000000400 */ +#define MiB 1048576u /* Mebi 0x0000000000100000 */ +#define GiB 1073741824u /* Gibi 000000000040000000 */ +#define TiB 1099511627776ull /* Tebi 0x0000010000000000 */ +#define PiB 1125899906842624ull /* Pebi 0x0004000000000000 */ +#define EiB 1152921504606846976ull /* Exbi 0x1000000000000000 */ + +/* + * Sizes + */ +#define BI2BY 8 /* bits per byte */ +#define BI2WD 32 /* bits per word */ +#define BY2WD 4 /* bytes per word */ +#define BY2V 8 /* bytes per vlong */ +#define BY2SE 4 /* bytes per stack element */ +#define BY2PG 4096 /* bytes per page */ +#define PGSHIFT 12 /* log(BY2PG) */ +#define STACKALIGN(sp) ((sp) & ~7) /* bug: assure with alloc */ +#define SEGALIGN (1024*1024) /* alignment for segments */ +#define BY2PTE 8 /* bytes per pte entry */ +#define BY2PTEG 64 /* bytes per pte group */ + +#define ICACHESIZE 32768 /* 0, 4, 8, 16, or 32 KB */ +#define ICACHEWAYSIZE (ICACHESIZE/64) /* 64-way set associative */ +#define ICACHELINELOG 5 /* 8 words (4 bytes) per line */ +#define ICACHELINESZ (1< */ +#define USER 29 /* R29 is up-> */ + +/* + * Virtual MMU + */ +#define PTEMAPMEM (1024*1024) +#define PTEPERTAB (PTEMAPMEM/BY2PG) +#define SEGMAPSIZE 1984 +#define SSEGMAPSIZE 16 +#define PPN(x) ((x)&~(BY2PG-1)) + +#define PTEVALID (1<<0) +#define PTEWRITE (1<<1) +#define PTERONLY (0<<1) +#define PTEUNCACHED (1<<2) + +/* + * Physical MMU + */ +#define NTLB 64 /* number of entries */ +#define NTLBPID 256 /* number of hardware pids (0 = global) */ + +/* TLBHI */ +#define TLBEPN(x) ((x) & ~0x3FF) +#define TLB1K (0<<4) +#define TLB4K (1<<4) +#define TLB16K (2<<4) +#define TLB64K (3<<4) +#define TLB256K (4<<4) +#define TLB1MB (5<<4) +/* 4Mbyte not implemented */ +#define TLB16MB (7<<4) +/* 32Mbyte not implemented */ +#define TLB256MB (9<<4) +#define TLBVALID (1<<9) +#define TLBTS (1<<8) /* Translation address space */ + +/* TLBMID */ +#define TLBRPN(x) ((x) & ~0x3FF) +#define TLBERPN(uv) (((uv)>>32)&0xF) /* with full address as uvlong */ + +/* TLBLO */ +#define TLBU0 (1<<15) /* user definable */ +#define TLBU1 (1<<14) /* user definable */ +#define TLBU2 (1<<13) /* user definable */ +#define TLBU3 (1<<12) /* user definable */ +#define TLBW (1<<11) /* write-through? */ +#define TLBI (1<<10) /* cache inhibit */ +#define TLBM (1<<9) /* memory coherent */ +#define TLBG (1<<8) /* guarded */ +#define TLBLE (1<<7) /* little endian mode */ +#define TLBUX (1<<5) /* user execute enable */ +#define TLBUW (1<<4) /* user writable */ +#define TLBUR (1<<3) /* user readable */ +#define TLBSX (1<<2) /* supervisor execute enable */ +#define TLBSW (1<<1) /* supervisor writable */ +#define TLBSR (1<<0) /* supervisor readable */ + +#define TLBWR (TLBSW|TLBSR) + +/* + * software TLB (for quick reload by [id]tlbmiss) + */ +#define STLBLOG 10 +#define STLBSIZE (1<[2]/dev/null) ; bind -c . .; bind -a ../vt4 . } + +CONF=vt5cpu +CONFLIST=vt5cpu + +loadaddr=0x80100020 +physaddr=0x00100020 +pagesize=0x100000 + +objtype=power +$target.list + size $target + +$p$CONF.elf:DQ: $CONF.$O $OBJ $LIB + echo '# linking elf kernel' + $LD -H5 -R$pagesize -T$loadaddr -P$physaddr -o $target -l $OBJ $CONF.$O $LIB + +$p$CONF.gz:D: $p$CONF + gzip -9 <$p$CONF >$target + +$OBJ: $HFILES + +install:V: /$objtype/$p$CONF + +/$objtype/$p$CONF:D: $p$CONF $p$CONF.elf + cp -x $p$CONF $p$CONF.elf /$objtype + { 9fs lookout && cp -x $p$CONF $p$CONF.elf /n/lookout/$objtype } & + { 9fs piestand && cp -x $p$CONF $p$CONF.elf /n/piestand/$objtype } & + { 9fs slocum && cp -x $p$CONF.list /n/slocum/home/rae/hbsr/ml510_ddr2 } & + wait + touch $target + +archvt5.$O: io.h reboot.h +devboot.$O: ../port/error.h +devether.$O: ../port/error.h ../port/netif.h etherif.h +etherlltemac.$O: ../port/netif.h etherif.h io.h +fpi.$O: fpi.h +fpimem.$O: fpi.h +fpipower.$O: /$objtype/include/ureg.h fpi.h +fpu.$O: /$objtype/include/ureg.h +main.$O: /sys/include/pool.h /sys/include/tos.h init.h reboot.h +syscall.$O: ../port/error.h +syscall.$O: /sys/include/tos.h /$objtype/include/ureg.h +trap.$O: /sys/include/tos.h /$objtype/include/ureg.h io.h +uartlite.$O: ../port/error.h io.h +random.$O: ../port/error.h + +%.$O: ../boot/%.c # don't use kernel CFLAGS + $CC -FTVw ../boot/$stem.c + +init.out:D: init9.$O initcode.$O /$objtype/lib/libc.a + $LD -l -R8 -s -o $target init9.$O initcode.$O -lc + +init.h: init.out + {echo 'uchar initcode[]={' + xd -1x $prereq | + sed -e 's/^[0-9a-f]+ //' -e 's/ ([0-9a-f][0-9a-f])/0x\1,/g' + echo '};'} >$target + +reboot.out:D: rebootcode.$O + # -lc is only for memmove. -T arg is REBOOTADDR + $LD -l -a -s -T0x80002640 -R4 -o $target rebootcode.$O -lc >reboot.list + +reboot.h:D: reboot.out + {echo 'uchar rebootcode[]={' + xd -1x $prereq | + sed -e '1,2d' -e 's/^[0-9a-f]+ //' -e 's/ ([0-9a-f][0-9a-f])/0x\1,/g' + echo '};'} >$target + +$CONF.clean: + if (! unmount . >[2]/dev/null) + ; + rm -rf $p$CONF $p$CONF.elf $CONF.c boot$CONF.c ../boot/libboot.a$O reboot.h diff -Nru /sys/src/9/vt5/mmu.c /sys/src/9/vt5/mmu.c --- /sys/src/9/vt5/mmu.c Thu Jan 1 00:00:00 1970 +++ /sys/src/9/vt5/mmu.c Fri Jun 7 00:00:00 2013 @@ -0,0 +1,404 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" + +/* + * 440 mmu + * + * l.s has set some global TLB entries for the kernel at + * the top of the tlb (NTLB-1 down), partly to account for + * the way the firmware sets things up on some platforms (eg, 440). + * The first entry not used by the kernel (eg, by kmapphys) is m->utlbhi. + * User tlbs are assigned indices from 0 to m->utlbhi, round-robin. + * m->utlbnext is the next to use. Kernel tlbs are added at utlbhi, which then moves. + * + * In this version, the kernel TLB entries are in zone 0, + * and user pages are in zone 1. The kernel entries are also PID 0 (global) + * so they are usable as the PID changes (0=no user; non-zero=user process mapped). + */ + +enum { + Minutlb= NTLB/2, /* at least this many for user process */ +}; + +#define DEBUG 0 + +Softtlb softtlb[MAXMACH][STLBSIZE]; + +static int newtlbpid(Proc*); +static void purgetlb(int); +static void putstlb(int, u32int, u32int, u32int); + +static int +lookstlb(int pid, u32int va) +{ + int i; + + pid <<= 2; + i = ((va>>12)^pid)&(STLBSIZE-1); + if(m->stlb[i].hi == (va|pid)) + return i; + + return -1; +} + +void +tlbdump(char *s) +{ + int i, p; + u32int hi, lo, mi, stid; + + p = pidget(); + iprint("tlb[%s] pid %d lastpid %d utlbnext %d\n", + s, p, m->lastpid, m->utlbnext); + for(i=0; iutlbhi) + iprint("-----\n"); + } + stidput(p); /* tlbrehi changes STID */ +} + +void +alltlbdump(void) +{ + Mreg s; + Proc *p; + int i, machno; + + s = splhi(); + machno = m->machno; + iprint("cpu%d pidproc:\n", machno); + for(i=0; ipidproc); i++){ + p = m->pidproc[i]; + if(p != nil && (p->mmupid != i || p == up)) + iprint("%d -> %ld [%d]\n", i, p->pid, p->mmupid); + } + tlbdump("final"); + splx(s); +} + +/* + * l.s provides a set of tlb entries for the kernel, allocating + * them starting at the highest index down. user-level entries + * will be allocated from index 0 up. + */ +void +mmuinit(void) +{ + int i; + + pidput(0); + stidput(0); + m->stlb = softtlb[m->machno]; + if(DEBUG) + tlbdump("init0"); + + m->lastpid = 0; + m->utlbhi = 0; + for(i = 0; i < NTLB; i++){ + if(tlbrehi(i) & TLBVALID) + break; + m->utlbhi = i; + stidput(0); + tlbwrx(i, 0, 0, 0); + } + pidput(0); + stidput(0); + if(DEBUG) + tlbdump("init1"); +} + +void +flushmmu(void) +{ + Mreg s; + + s = splhi(); + up->newtlb = 1; + mmuswitch(up); + splx(s); +} + +/* + * called with splhi + */ +void +mmuswitch(Proc *p) +{ + int pid; + + if(p->newtlb){ + p->mmupid = 0; + p->newtlb = 0; + } + pid = p->mmupid; + if(pid == 0 && !p->kp) + pid = newtlbpid(p); + pidput(pid); + stidput(pid); +} + +void +mmurelease(Proc* p) +{ + p->mmupid = 0; + pidput(0); + stidput(0); +} + +void +putmmu(uintptr va, uintptr pa, Page* page) +{ + Mreg s; + int x, tp; + char *ctl; + u32int tlbhi, tlblo, tlbmi; + + if(va >= KZERO) + panic("mmuput"); + + tlbhi = TLBEPN(va) | TLB4K | TLBVALID; + tlbmi = TLBRPN(pa); /* TO DO: 36-bit physical memory */ + tlblo = TLBUR | TLBUX | TLBSR; /* shouldn't need TLBSX */ + if(pa & PTEWRITE) + tlblo |= TLBUW | TLBSW; + if(pa & PTEUNCACHED) + tlblo |= TLBI | TLBG; + + s = splhi(); + tp = up->mmupid; + if(tp == 0){ + if(up->kp) + panic("mmuput kp"); + tp = newtlbpid(up); + pidput(tp); + stidput(tp); + } + else if(pidget() != tp || stidget() != tp){ + iprint("mmuput: cpu%d pid up->mmupid=%d pidget=%d stidget=%d s=%#ux\n", + m->machno, tp, pidget(), stidget(), s); + alltlbdump(); + panic("mmuput: cpu%d pid %d %d s=%#ux", + m->machno, tp, pidget(), s); + } + + /* see if it's already there: note that tlbsx[cc] uses STID */ + x = tlbsxcc(va); + if(x < 0){ + if(m->utlbnext > m->utlbhi) + m->utlbnext = 0; + x = m->utlbnext++; + }else if(x > m->utlbhi) + panic("mmuput index va=%#p x=%d klo=%d", va, x, m->utlbhi); /* shouldn't touch kernel entries */ +// if(DEBUG) +// iprint("put %#p %#p-> %d: %8.8ux %8.8ux %8.8ux\n", va, pa, x, tlbhi, tlbmi, tlblo); + if(stidget() != tp) + panic("mmuput stid:pid mismatch"); + stidput(tp); + tlbwrx(x, tlbhi, tlbmi, tlblo); + putstlb(tp, TLBEPN(va), tlbmi, tlblo); + + ctl = &page->cachectl[m->machno]; + switch(*ctl){ + case PG_TXTFLUSH: + dcflush(page->va, BY2PG); + icflush(page->va, BY2PG); + *ctl = PG_NOFLUSH; + break; + case PG_DATFLUSH: + dcflush(page->va, BY2PG); + *ctl = PG_NOFLUSH; + break; + case PG_NEWCOL: +// cleancache(); /* expensive, but fortunately not needed here */ + *ctl = PG_NOFLUSH; + break; + } + splx(s); +} + +/* + * Process must be splhi + */ +static 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] == nil) + break; + } + + if(h[i] != nil){ + purgetlb(i); + if(h[i] != nil) + panic("newtlb"); + } + + m->pidproc[i] = p; + p->mmupid = i; + m->lastpid = i; + + return i; +} + +static void +purgetlb(int pid) +{ + int i; + Proc *sp, **pidproc; + Softtlb *entry, *etab; + u32int hi; + + m->tlbpurge++; + + /* + * find all pid entries that are no longer used by processes + */ + pidproc = m->pidproc; + for(i=1; immupid != i) + pidproc[i] = nil; + } + + /* + * shoot down the one we want + */ + sp = pidproc[pid]; + if(sp != nil) + sp->mmupid = 0; + pidproc[pid] = nil; + + /* + * clean out all dead pids from the stlb; + */ + entry = m->stlb; + for(etab = &entry[STLBSIZE]; entry < etab; entry++) + if(pidproc[(entry->hi>>2)&0xFF] == nil){ + entry->hi = 0; + entry->mid = 0; + entry->lo = 0; + } + + /* + * clean up the hardware + */ + for(i = 0; i <= m->utlbhi; i++){ + hi = tlbrehi(i); + if((hi & TLBVALID) && pidproc[stidget()] == nil) + tlbwrx(i, 0, 0, 0); + } + stidput(pidget()); + mbar(); + barriers(); + iccci(); +} + +/* + * return required size and alignment to map n bytes in a tlb entry + */ +ulong +mmumapsize(ulong n) +{ + ulong size; + int i; + + size = 1024; + for(i = 0; i < 10 && size < n; i++) + size <<= 2; + return size; +} + +/* + * map a physical addresses at pa to va, with the given attributes. + * the virtual address must not be mapped already. + * if va is nil, map it at pa in virtual space. + */ +void* +kmapphys(uintptr va, uintptr pa, ulong nb, ulong attr, ulong le) +{ + Mreg s; + int i; + ulong size; + + if(va == 0) + va = pa; /* simplest is to use a 1-1 map */ + size = 1024; + for(i = 0; i < 10 && size < nb; i++) + size <<= 2; + if(i >= 10) + return 0; + if(i == 6 || i == 8) + i++; /* skip sizes not implemented by hardware */ + if(m->utlbhi <= Minutlb) + panic("kmapphys"); + + s = splhi(); + stidput(0); + tlbwrx(m->utlbhi, va | (i<<4) | TLBVALID, pa, attr | le); + m->utlbhi--; + stidput(pidget()); + splx(s); + + if(DEBUG) + tlbdump("kmapphys"); + + return UINT2PTR(va); +} + +/* + * return an uncached alias for the memory at a + */ +void* +mmucacheinhib(void* a, ulong nb) +{ + uintptr pa; + + if(a == nil) + return nil; + dcflush(PTR2UINT(a), nb); + pa = PADDR(a); + return kmapphys(KSEG1|pa, pa, nb, TLBWR | TLBI | TLBG, 0); +} + +static void +putstlb(int pid, u32int va, u32int tlbmid, u32int tlblo) +{ + Softtlb *entry; + + pid <<= 2; + entry = &m->stlb[((va>>12)^pid)&(STLBSIZE-1)]; + entry->hi = va | pid; + entry->mid = tlbmid; + entry->lo = tlblo; +} + +/* + * Return the number of bytes that can be accessed via KADDR(pa). + * If pa is not a valid argument to KADDR, return 0. + */ +uintptr +cankaddr(uintptr pa) +{ + if( /* pa >= PHYSDRAM && */ pa < PHYSDRAM + 512*MiB) + return PHYSDRAM + 512*MiB - pa; + return 0; +} diff -Nru /sys/src/9/vt5/physmem.h /sys/src/9/vt5/physmem.h --- /sys/src/9/vt5/physmem.h Thu Jan 1 00:00:00 1970 +++ /sys/src/9/vt5/physmem.h Fri Jun 7 00:00:00 2013 @@ -0,0 +1,35 @@ +/* + * Memory-mapped IO + */ + +/* + * virtex5 system loses top 1/5th of 512MB to ECC in the secure memory system. + */ +#define MEMTOP(phys) ((((((phys)/32)*4)/5) * 8*BY2WD) & -128) +// #define MAXMEM (512*MB) +#define MAXMEM (256*MB) + +/* memory map for rae's virtex5 design */ +#define PHYSDRAM 0 +#define PHYSSRAM 0xfffe0000 /* 128K long, in top 128M */ + +#define PHYSMMIO Io + +#define Io 0xf0000000 /* ~512K of IO registers */ +#define Uartlite 0xf0000000 +#define Gpio 0xf0010000 +#define Intctlr 0xf0020000 +#define Temac 0xf0030000 +#define Llfifo 0xf0040000 +#define Dmactlr 0xf0050000 +#define Dmactlr2 0xf0060000 +/* + * if these devices exist in a given hardware configuration, + * they will be at these addresses. + */ +#define Qtm 0xf0070000 /* encrypted memory control */ +#define Mpmc 0xf0080000 /* multi-port memory controller */ +/* setting low bit interrupts cpu0; don't set Hie */ +#define Intctlr2 0xf0090000 /* sw interrupt controller */ + +#define VECBASE PHYSDRAM /* vectors need to be near(ish) handlers */ diff -Nru /sys/src/9/vt5/rebootcode.s /sys/src/9/vt5/rebootcode.s --- /sys/src/9/vt5/rebootcode.s Thu Jan 1 00:00:00 1970 +++ /sys/src/9/vt5/rebootcode.s Fri Jun 7 00:00:00 2013 @@ -0,0 +1,199 @@ +/* virtex5 ppc440x5 reboot code */ +#include "mem.h" + +#define SPR_SRR0 26 /* Save/Restore Register 0 */ +#define SPR_SRR1 27 /* Save/Restore Register 1 */ +#define SPR_DBCR0 0x134 /* Debug Control Register 0 */ +#define SPR_DBCR1 0x135 /* Debug Control Register 1 */ +#define SPR_DBCR2 0x136 /* Debug Control Register 1 */ +#define SPR_DBSR 0x130 /* Debug Status Register */ + +/* special instruction definitions */ +#define BDNZ BC 16,0, +#define BDNE BC 0,2, + +#define ICCCI(a,b) WORD $((31<<26)|((a)<<16)|((b)<<11)|(966<<1)) +#define DCCCI(a,b) WORD $((31<<26)|((a)<<16)|((b)<<11)|(454<<1)) + +/* + * on the 400 series, the prefetcher madly fetches across RFI, sys call, + * and others; use BR 0(PC) to stop. + */ +#define RFI WORD $((19<<26)|(50<<1)); BR 0(PC) +#define RFCI WORD $((19<<26)|(51<<1)); BR 0(PC) + +/* print progress character. steps on R7 and R8, needs SB set. */ +#define PROG(c) MOVW $(Uartlite+4), R7; MOVW $(c), R8; MOVW R8, 0(R7); SYNC + +/* + * copied to REBOOTADDR and executed there. + * since it copies the new kernel over the old one, it is + * self-contained and does not call any other kernel code. + * + * Turn off interrupts, then copy the new kernel to its correct location + * in physical memory. Then jump to the start of the kernel. + * destination and source arguments are virtual addresses. + */ + + NOSCHED + +TEXT main(SB),1,$-4 + MOVW $setSB(SB), R2 + + MOVW R3, p1+0(FP) /* destination, passed in R3 */ + MOVW R3, R6 /* entry point */ + MOVW p2+4(FP), R4 /* source */ + MOVW n+8(FP), R5 /* byte count */ + + /* make it safe to copy over the old kernel */ +PROG('R') + BL introff(SB) +// MOVW $setSB(SB), R2 + +PROG('e') +// BL resetcaches(SB) + + /* disable debug facilities */ + ISYNC + MOVW R0, SPR(SPR_DBCR0) + MOVW R0, SPR(SPR_DBCR1) + MOVW R0, SPR(SPR_DBCR2) + ISYNC + MOVW $~0, R7 + MOVW R7, SPR(SPR_DBSR) + ISYNC + + MOVW R3, R1 /* tiny trampoline stack before dest */ + SUB $0x20, R1 /* bypass a.out header */ + + /* copy new kernel over the old */ + MOVWU R0, -48(R1) /* allocate stack frame */ + MOVW R3, 44(R1) /* save dest */ + MOVW R5, 40(R1) /* save count */ + MOVW R3, 0(R1) + MOVW R3, 4(R1) /* push dest */ + MOVW R4, 8(R1) /* push src */ + MOVW R5, 12(R1) /* push size */ +PROG('s') + BL memmove(SB) + SYNC + MOVW 44(R1), R6 /* restore dest */ + MOVW p2+4(FP), R4 /* restore source */ + MOVW 40(R1), R5 /* restore count */ + + /* verify that we copied it correctly */ +PROG('t') + MOVW R4, R10 + MOVW R6, R11 + MOVW R5, R12 + SUB $4, R10 + SUB $4, R11 +cmploop: + MOVWU 4(R10), R13 + MOVWU 4(R11), R14 + CMP R13, R14 + BNE buggered + SUB $4, R12 + CMP R12, R0 + BGT cmploop + +PROG('a') + ANDCC $~KZERO, R6, R3 /* physical entry addr */ + + MOVW R0, R4 + SUB $(4*2), R4 /* r4 is now points to bootstart */ + MOVW R3, 0(R4) /* entry addr into bootstart */ + SYNC + ISYNC + +PROG('r') + /* + * flush data cache + */ + MOVW R6, R3 /* virtaddr */ + MOVW R5, R4 /* count */ + RLWNM $0, R3, $~(DCACHELINESZ-1), R5 + CMP R4, R0 + BLE dcf1 + SUB R5, R3 + ADD R3, R4 + ADD $(DCACHELINESZ-1), R4 + SRAW $DCACHELINELOG, R4 + MOVW R4, CTR +dcf0: DCBF (R5) + ADD $DCACHELINESZ, R5 + BDNZ dcf0 +dcf1: + SYNC + ISYNC + + /* be sure icache is cleared */ + BL resetcaches(SB) + +/* + * jump to kernel entry point. Note the true kernel entry point is + * the virtual address R6, and the MMU is always enabled. + */ + OR R6, R6 /* NOP: avoid link bug */ + MOVW R6, LR +PROG('t') +PROG('\r') +PROG('\n') + BL (LR) /* without reset. leaves qtm, dram, etc. intact */ + BR 0(PC) + +// BR reset +buggered: + PROG('C') + PROG('m') + PROG('p') + PROG(' ') + PROG('f') + PROG('a') + PROG('i') + PROG('l') +reset: + ISYNC + MOVW $(3<<28), R3 + MOVW R3, SPR(SPR_DBCR0) /* cause a system reset */ + ISYNC + BR 0(PC) + +TEXT introff(SB), 1, $-4 + MOVW LR, R7 + MOVW R7, SPR(SPR_SRR0) + + /* + * turn off interrupts & MMU + * disable machine check + */ + MOVW MSR, R7 + RLWNM $0, R7, $~(MSR_EE), R7 + RLWNM $0, R7, $~(MSR_CE), R7 + RLWNM $0, R7, $~(MSR_DE), R7 + RLWNM $0, R7, $~(MSR_ME), R7 + RLWNM $0, R7, $~(MSR_IS|MSR_DS), R7 + MOVW R7, SPR(SPR_SRR1) + SYNC /* fix 405 errata cpu_210 */ + RFI /* resume in kernel mode in caller */ + +/* + * reset the caches + * clobbers R7 + */ +TEXT resetcaches(SB),1,$-4 + ICCCI(0, 2) /* errata cpu_121 reveals that EA is used; we'll use SB */ + ISYNC + + MOVW $(DCACHEWAYSIZE/DCACHELINESZ), R7 + MOVW R7, CTR + MOVW $KZERO, R7 +dcinv: + DCBF (R7) + ADD $DCACHELINESZ, R7 + BDNZ dcinv + + SYNC; ISYNC + + BR (LR) + BR 0(PC) diff -Nru /sys/src/9/vt5/tlb.s /sys/src/9/vt5/tlb.s --- /sys/src/9/vt5/tlb.s Thu Jan 1 00:00:00 1970 +++ /sys/src/9/vt5/tlb.s Fri Jun 7 00:00:00 2013 @@ -0,0 +1,49 @@ +/* virtex5 ppc440x5 initial tlb entries */ +#include "mem.h" +#define MB (1024*1024) + +/* + * TLB prototype entries, loaded once-for-all at startup, + * remaining unchanged thereafter. + * Limit the table size to ensure it fits in small TLBs. + */ +#define TLBE(hi, md, lo) WORD $(hi); WORD $(md); WORD $(lo) + +/* + * WARNING: applying TLBG to instruction pages will cause ISI traps + * on Xilinx 405s, despite the words of most of the Xilinx manual + * (e.g., UG011, p. 155). p. 153 has the (insufficiently bold-faced) + * warning: ``In virtual mode, attempts to fetch instructions either + * from guarded storage or from no-execute memory locations normally + * cause an instruction-storage interrupt [i.e., trap or exception] + * to occur.'' In other words, WARNING: LARKS' VOMIT! + * + * Using write-back caches requires more care with cache flushing + * and use of memory barriers, but cuts run times to about 40% of + * what we see with write-through caches (using the TLBW bit). + * The low 4 bits of the middle word are high bits (33-36) of the RPN; + * we set them to zero. + * On the virtex 5, TLBM doesn't do anything, alas. + */ + +TEXT tlbtab(SB), 1, $-4 + /* DRAM, at most 512MB */ + TLBE(KZERO | PHYSDRAM | TLB256MB | TLBVALID, PHYSDRAM, + TLBSR | TLBSX | TLBSW) + TLBE(KZERO | PHYSDRAM+(256*MB) | TLB256MB | TLBVALID, PHYSDRAM+(256*MB), + TLBSR | TLBSX | TLBSW) + + /* memory-mapped IO, 1MB, 0xf0000000—0xf00fffff */ + TLBE(PHYSMMIO | TLB1MB | TLBVALID, PHYSMMIO, + TLBSR | TLBSW | TLBI | TLBG) + + /* + * SRAM, 128K. put vectors here. + */ + TLBE(PHYSSRAM | TLB64K | TLBVALID, PHYSSRAM, + TLBSR | TLBSX | TLBSW) + TLBE(PHYSSRAM+64*1024 | TLB64K | TLBVALID, PHYSSRAM+64*1024, + TLBSR | TLBSX | TLBSW) + +TEXT tlbtabe(SB), 1, $-4 + RETURN diff -Nru /sys/src/9/vt5/trap.c /sys/src/9/vt5/trap.c --- /sys/src/9/vt5/trap.c Thu Jan 1 00:00:00 1970 +++ /sys/src/9/vt5/trap.c Fri Jun 7 00:00:00 2013 @@ -0,0 +1,643 @@ +/* ppc440 traps */ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" + +#include +#include "ureg.h" + +#include "io.h" + +enum { + VECSIZE = 0x100, +}; + +extern int notify(Ureg*); +extern void syscall(Ureg*); + +static struct { + ulong off; + char *name; +} intcause[] = { + { INT_CI, "critical input" }, + { INT_MCHECK, "machine check" }, + { INT_DSI, "data access" }, + { INT_ISI, "instruction access" }, + { INT_EI, "external interrupt" }, + { INT_ALIGN, "alignment" }, + { INT_PROG, "program exception" }, + { INT_FPU, "floating-point unavailable" }, + { INT_DEC, "decrementer" }, + { INT_SYSCALL, "system call" }, + { INT_TRACE, "trace trap" }, + { INT_FPA, "floating point unavailable" }, + { INT_APU, "auxiliary processor unavailable" }, + { INT_PIT, "programmable interval timer interrrupt" }, + { INT_FIT, "fixed interval timer interrupt" }, + { INT_WDT, "watch dog timer interrupt" }, + { INT_DMISS, "data TLB miss" }, + { INT_IMISS, "instruction TLB miss" }, + { INT_DEBUG, "debug interrupt" }, + { INT_DEBUG+VECSIZE, "system reset" }, + { 0, "unknown interrupt" } +}; + +static char *excname(ulong, u32int); + +char *regname[]={ + "CAUSE","SRR1", + "PC", "GOK", + "LR", "CR", + "XER", "CTR", + "R0", "R1", + "R2", "R3", + "R4", "R5", + "R6", "R7", + "R8", "R9", + "R10", "R11", + "R12", "R13", + "R14", "R15", + "R16", "R17", + "R18", "R19", + "R20", "R21", + "R22", "R23", + "R24", "R25", + "R26", "R27", + "R28", "R29", + "R30", "R31", +}; + +static int probing, trapped; + +void init0(void); + +#define SPR(v) (((v&0x1f)<<16) | (((v>>5)&0x1f)<<11)) + +#define SPR_SPRG0 0x110 /* SPR General 0 */ +#define SPR_SPRG2 0x112 /* SPR General 2 */ +#define SPR_SPRG6W 0x116 /* SPR General 6; supervisor W */ + +static void +vecgen(int v, void (*r)(void), int r0spr, int maskce) +{ + u32int *vp, o, ra; + int i, d; + + vp = (u32int*)KADDR(v); + vp[0] = 0x7c0003a6 | SPR(r0spr); /* MOVW R0, SPR(r0spr) */ + i = 1; + if(maskce){ /* clear CE? this stops crit. intrs. */ + vp[i++] = 0x7c0000a6; /* MOVW MSR, R0 */ + vp[i++] = 0x540003da; /* RLWNM $0, R0, ~MSR_CE, R0 */ + vp[i++] = 0x7c000124; /* MOVW R0, MSR */ + } + vp[i++] = 0x7c0802a6; /* MOVW LR, R0 */ + vp[i++] = 0x7c0003a6 | SPR(SPR_SPRG2); /* MOVW R0, SPR(SPRG2) */ + d = (uchar*)r - (uchar*)&vp[i]; + o = (u32int)d >> 25; + if(o != 0 && o != 0x7F){ + /* a branch too far: running from ROM */ + ra = (u32int)r; + vp[i++] = (15<<26)|(ra>>16); /* MOVW $r&~0xFFFF, R0 */ + vp[i++] = (24<<26)|(ra&0xFFFF); /* OR $r&0xFFFF, R0 */ + vp[i++] = 0x7c0803a6; /* MOVW R0, LR */ + vp[i++] = 0x4e800021; /* BL (LR) */ + }else + vp[i++] = (18<<26)|(d&0x3FFFFFC)|1; /* bl (relative) */ + dcflush(PTR2UINT(vp), i*sizeof(u32int)); +} + +/* populate a normal vector */ +static void +sethvec(int v, void (*r)(void)) +{ + vecgen(v, r, SPR_SPRG0, 1); +} + +/* populate a tlb-miss vector */ +static void +sethvec2(int v, void (*r)(void)) +{ + ulong *vp; + long d; + + vp = (ulong*)KADDR(v); + d = (uchar*)r - (uchar*)&vp[0]; + if (d >= (1<<26)) { + uartlputc('?'); +iprint("sethvec2: v %#x vp %#p r %#p d %ld\n", v, vp, r, d); + iprint("tlb miss handler address too high\n"); + } + vp[0] = (18<<26)|(d & 0x3FFFFFC); /* b (relative) */ + dcflush(PTR2UINT(vp), sizeof *vp); +} + +static void +faultpower(Ureg *ureg, ulong addr, int read) +{ + int user, insyscall; + char buf[ERRMAX]; + + /* + * There must be a user context. + * If not, the usual problem is causing a fault during + * initialisation before the system is fully up. + */ + user = (ureg->srr1 & MSR_PR) != 0; + if(!user){ +// if(vmapsync(addr)) +// return; +// if(addr >= USTKTOP) +// panic("kernel fault: bad address pc=%.8#lux addr=%.8#lux", +// ureg->pc, addr); + if(up == nil) + panic("kernel fault: no user process pc=%.8#lux addr=%.8#lux", + ureg->pc, addr); + } + if(up == nil) + panic("user fault: up=0 pc=%.8#lux addr=%.8#lux", ureg->pc, addr); + insyscall = up->insyscall; + up->insyscall = 1; + if(fault(addr, read) < 0){ + /* + * It is possible to get here with !user if, for example, + * a process was in a system call accessing a shared + * segment but was preempted by another process which shrunk + * or deallocated the shared segment; when the original + * process resumes it may fault while in kernel mode. + * No need to panic this case, post a note to the process + * and unwind the error stack. There must be an error stack + * (up->nerrlab != 0) if this is a system call, if not then + * the game's a bogey. + */ + if(!user && (!insyscall || up->nerrlab == 0)){ + dumpregs(ureg); + panic("fault: %#lux", addr); + } + sprint(buf, "sys: trap: fault %s addr=%#lux", + read? "read": "write", addr); + postnote(up, 1, buf, NDebug); + if(insyscall) + error(buf); + } + up->insyscall = insyscall; +} + +static void +setlights(int user) +{ + if (up == nil) + lightstate(Ledidle); + else + lightstate(user == 0? Ledkern: Leduser); +} + +void +syncall(void) +{ + sync(); + isync(); +} + +void +kexit(Ureg*) +{ + uvlong t; + Tos *tos; + + /* precise time accounting, kernel exit */ + tos = (Tos*)(USTKTOP-sizeof(Tos)); + cycles(&t); + tos->kcycles += t - up->kentry; + tos->pcycles = up->pcycles; + tos->pid = up->pid; +// surely only need to set tos->pid on rfork and exec? +} + +void +trap(Ureg *ur) +{ + int ecode, user, v; + u32int esr, mcsr; + char buf[ERRMAX]; + + if (ur == nil) + panic("trap: nil ur"); + v = ur->cause; + ur->cause &= 0xFFE0; + ecode = ur->cause; + + esr = getesr(); + mcsr = getmcsr(); + clrmchk(); + + lightstate(Ledtrap); + user = (ur->srr1 & MSR_PR) != 0; + if(user){ + cycles(&up->kentry); + up->dbgreg = ur; + } + switch(ecode){ + case INT_SYSCALL: + if(!user) + panic("syscall in kernel: srr1 %#4.4luX pc %#p", + ur->srr1, ur->pc); + syscall(ur); + setlights(user); + return; /* syscall() calls notify itself */ + + case INT_PIT: + m->intr++; + clockintr(ur); + break; + + case INT_WDT: + puttsr(~0); + panic("watchdog timer went off at pc %#lux", ur->pc); + break; + + case INT_MCHECK: + if (probing && !user) { + if (trapped++ > 0) + panic("trap: recursive probe on mcheck"); + break; /* continue at next instruction */ + } + if(esr & ESR_MCI){ + iprint("mcheck-mci %lux\n", ur->pc); + faultpower(ur, ur->pc, 1); + break; + } + iprint("mcheck %#lux esr=%#ux mcsr=%#ux dear=%#ux\n", + ur->pc, esr, mcsr, getdear()); + ur->pc -= 4; /* back up to faulting instruction */ + /* fall through */ + case INT_DSI: + case INT_DMISS: + faultpower(ur, getdear(), !(esr&ESR_DST)); + break; + + case INT_ISI: + case INT_IMISS: + faultpower(ur, ur->pc, 1); + break; + + case INT_CI: + case INT_EI: + m->intr++; + intr(ur); + break; + + case 0: + puttsr(~0); + if (v == 0) + panic("watchdog reset? probable jump via " + "zeroed pointer; pc %#lux lr %#lux", + ur->pc, ur->lr); + else + panic("watchdog reset? interrupt at vector zero; " + "pc %#lux lr %#lux", ur->pc, ur->lr); + break; + + case INT_DEBUG: + putdbsr(~0); /* extinguish source */ + print("debug interrupt at pc %#lux\n", ur->pc); + break; + + case INT_DEBUG + VECSIZE: + panic("reset"); + break; + + case INT_FPA: + case INT_FPU: + if(fpuavail(ur)) + break; + esr |= ESR_PFP; + /* fall through */ + case INT_PROG: + if(esr & ESR_PFP){ /* floating-point enabled exception */ + fputrap(ur, user); + break; + } + if(esr & ESR_PIL && user){ + if(fpuemu(ur)) + break; + /* otherwise it's an illegal instruction */ + } + /* fall through */ + default: + if(user){ + spllo(); + sprint(buf, "sys: trap: %s", excname(ecode, esr)); + if(ecode == INT_ALIGN) + sprint(buf+strlen(buf), " ea=%#ux", getdear()); + postnote(up, 1, buf, NDebug); + break; + } + splhi(); + print("kernel %s; vector=%#ux pc=%#lux\n", + excname(ecode, esr), ecode, ur->pc); + if (ecode == 0) + print("probable jump via zeroed pointer; pc %#lux lr %#lux\n", + ur->pc, ur->lr); + dumpregs(ur); + dumpstack(); + if(m->machno == 0) + spllo(); + exit(1); + } + splhi(); + setlights(user); + + /* delaysched set because we held a lock or because our quantum ended */ + if(up && up->delaysched && ecode == INT_PIT){ + sched(); + splhi(); + setlights(user); + } + + if(user){ + if(up->procctl || up->nnote) + notify(ur); + kexit(ur); + } +} + +void +trapinit(void) +{ + int i; + + clrmchk(); + intrinit(); + + /* + * set all exceptions to trap by default + */ + for(i = 0; i < INT_DEBUG + VECSIZE; i += VECSIZE) + sethvec(VECBASE + i, trapvec); + + /* + * set exception handlers + */ + vecgen(VECBASE + INT_CI, critintrvec, SPR_SPRG6W, 0); + sethvec(VECBASE + INT_MCHECK, trapmvec); + sethvec(VECBASE + INT_DSI, trapvec); + sethvec(VECBASE + INT_ISI, trapvec); + sethvec(VECBASE + INT_EI, trapvec); + sethvec(VECBASE + INT_ALIGN, trapvec); + sethvec(VECBASE + INT_PROG, trapvec); + sethvec(VECBASE + INT_FPU, trapvec); + sethvec(VECBASE + INT_DEC, trapvec); + sethvec(VECBASE + INT_SYSCALL, trapvec); + sethvec(VECBASE + INT_TRACE, trapvec); + sethvec(VECBASE + INT_FPA, trapvec); + sethvec(VECBASE + INT_APU, trapvec); + sethvec(VECBASE + INT_PIT, trapvec); +// sethvec(VECBASE + INT_FIT, trapvec); + vecgen(VECBASE + INT_WDT, critintrvec, SPR_SPRG6W, 0); + sethvec2(VECBASE + INT_DMISS, dtlbmiss); + sethvec2(VECBASE + INT_IMISS, itlbmiss); + vecgen(VECBASE + INT_DEBUG, critintrvec, SPR_SPRG6W, 0); + sync(); + + putevpr(KZERO | VECBASE); + sync(); + + putmsr(getmsr() | MSR_ME | MSR_DE); + sync(); +} + +static char* +excname(ulong ivoff, u32int esr) +{ + int i; + + if(ivoff == INT_PROG){ + if(esr & ESR_PIL) + return "illegal instruction"; + if(esr & ESR_PPR) + return "privileged"; + if(esr & ESR_PTR) + return "trap with successful compare"; + if(esr & ESR_PEU) + return "unimplemented APU/FPU"; + if(esr & ESR_PAP) + return "APU exception"; + if(esr & ESR_U0F) + return "data storage: u0 fault"; + } + for(i=0; intcause[i].off != 0; i++) + if(intcause[i].off == ivoff) + break; + return intcause[i].name; +} + +/* + * Fill in enough of Ureg to get a stack trace, and call a function. + * Used by debugging interface rdb. + */ +void +callwithureg(void (*fn)(Ureg*)) +{ + Ureg ureg; + + ureg.pc = getcallerpc(&fn); + ureg.sp = PTR2UINT(&fn); + fn(&ureg); +} + +void +dumpstack(void) +{ + ulong l, v; + int i; + + if(up == 0) + return; + i = 0; + for(l=(ulong)&l; l<(ulong)(up->kstack+KSTACK); l+=4){ + v = *(ulong*)l; + if(KTZERO < v && v < (ulong)etext){ + iprint("%lux=%lux, ", l, v); + if(i++ == 4){ + iprint("\n"); + i = 0; + } + } + } +} + +void +dumpregs(Ureg *ureg) +{ + int i; + uintptr *l; + + splhi(); /* prevent recursive dumps */ + if(up != nil) + iprint("cpu%d: registers for %s %ld\n", + m->machno, up->text, up->pid); + else + iprint("cpu%d: registers for kernel\n", m->machno); + + if (ureg == nil) { + iprint("nil ureg, no dump\n"); + return; + } + l = &ureg->cause; + for(i = 0; i < nelem(regname); i += 2, l += 2) + iprint("%s\t%.8p\t%s\t%.8p\n", regname[i], l[0], regname[i+1], l[1]); +} + +static void +linkproc(void) +{ + spllo(); + up->kpfun(up->kparg); + pexit("", 0); +} + +void +kprocchild(Proc* p, void (*func)(void*), void* arg) +{ + p->sched.pc = PTR2UINT(linkproc); + p->sched.sp = PTR2UINT(p->kstack+KSTACK); + p->sched.sp = STACKALIGN(p->sched.sp); + + p->kpfun = func; + p->kparg = arg; +} + +uintptr +userpc(void) +{ + Ureg *ureg = up->dbgreg; + return ureg->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 *ureg, char *pureg, char *uva, int n) +{ + u32int status; + + status = ureg->status; + memmove(pureg, uva, n); + ureg->status = status; +} + +/* + * Give enough context in the ureg to produce a kernel stack for + * a sleeping process + */ +void +setkernur(Ureg* ureg, Proc* p) +{ + ureg->pc = p->sched.pc; + ureg->sp = p->sched.sp+BY2SE; +} + +uintptr +dbgpc(Proc* p) +{ + Ureg *ureg; + + ureg = p->dbgreg; + if(ureg == 0) + return 0; + + return ureg->pc; +} + +static Lock mchklck; /* only allow one probe or poke at a time */ + +vlong +probeaddr(uintptr addr) +{ + vlong v; + + ilock(&mchklck); + trapped = 0; + probing = 1; + + syncall(); + putmsr(getmsr() & ~MSR_ME); /* disable machine check traps */ + syncall(); + clrmchk(); + syncall(); + + if (getesr() & ESR_MCI) /* machine check happened? */ + iprint("probeaddr: mcheck before probe\n"); + v = *(ulong *)addr; /* this may cause a machine check */ + syncall(); + + if (getesr() & ESR_MCI) /* machine check happened? */ + trapped = 1; + syncall(); + clrmchk(); + syncall(); + putmsr(getmsr() | MSR_ME); /* enable machine check traps */ + syncall(); + + probing = 0; + if (trapped) + v = -1; +//iprint("probeaddr: trapped=%d for addr %lux\n", trapped, addr); + iunlock(&mchklck); + return v; +} + +vlong +pokeaddr(uintptr addr, uint v1, uint v2) +{ + vlong v; + ulong *p; + +//iprint("probing %#lux...", addr); + ilock(&mchklck); + trapped = 0; + probing = 1; + + syncall(); + putmsr(getmsr() & ~MSR_ME); /* disable machine check traps */ + syncall(); + clrmchk(); + syncall(); + + if (getesr() & ESR_MCI) /* machine check happened? */ + iprint("pokeaddr: mcheck before probe\n"); + + p = (ulong *)addr; + *p = v1; + syncall(); + v = *p; /* this may cause a machine check */ + syncall(); + if (getesr() & ESR_MCI || v != v1) /* machine check happened? */ + trapped = 1; + + *p = v2; + syncall(); + v = *p; /* this may cause a machine check */ + syncall(); + if (getesr() & ESR_MCI || v != v2) /* machine check happened? */ + trapped = 1; + + syncall(); + clrmchk(); + syncall(); + putmsr(getmsr() | MSR_ME); /* enable machine check traps */ + syncall(); + + probing = 0; + if (trapped) + v = -1; +//iprint("pokeaddr: trapped=%d for addr %lux\n", trapped, addr); + iunlock(&mchklck); + return v; +} diff -Nru /sys/src/9/vt5/vt5cpu /sys/src/9/vt5/vt5cpu --- /sys/src/9/vt5/vt5cpu Thu Jan 1 00:00:00 1970 +++ /sys/src/9/vt5/vt5cpu Fri Jun 7 00:00:00 2013 @@ -0,0 +1,60 @@ +# rae's virtex4 ppc405 fpga cpu server +dev + root + cons + env + pipe + proc + mnt + srv + dup +# rtc + arch + ssl + tls + cap + kprof +# aoe +# sd + + ether netif + ip arp chandial ip ipv6 ipaux iproute netlog nullmedium pktmedium ptclbsum inferno + + uart + +link + archvt5 + ethermedium + etherlltemac + loopbackmedium + netdevmedium + +ip + tcp + udp + ipifc + icmp + icmp6 + ipmux + +misc + dma + rdb +# sdaoe sdscsi + softfpu + syscall + uartlite +# ucalloc + +port + int cpuserver = 1; + int i8250freq = 3686000; + +boot cpu + tcp + +bootdir + boot$CONF.out boot + /power/bin/ip/ipconfig ipconfig + /power/bin/auth/factotum factotum + nvram