diff -Nru /sys/src/boot/vt4/archvt4.c /sys/src/boot/vt4/archvt4.c --- /sys/src/boot/vt4/archvt4.c Thu Jan 1 00:00:00 1970 +++ /sys/src/boot/vt4/archvt4.c Fri Jun 7 00:00:00 2013 @@ -0,0 +1,22 @@ +/* virtex 4 dependencies */ +#include "include.h" + +uvlong myhz = 300000000; /* fixed 300MHz */ +uchar mymac[Eaddrlen] = { 0x00, 0x0A, 0x35, 0x01, 0x8B, 0xB1 }; + +void +clrmchk(void) +{ + putesr(0); /* clears machine check */ +} + +/* + * virtex 4 systems always have 128MB. + */ +uintptr +memsize(void) +{ + uintptr sz = 128*MB; + + return securemem? MEMTOP(sz): sz; +} diff -Nru /sys/src/boot/vt4/boot.c /sys/src/boot/vt4/boot.c --- /sys/src/boot/vt4/boot.c Thu Jan 1 00:00:00 1970 +++ /sys/src/boot/vt4/boot.c Fri Jun 7 00:00:00 2013 @@ -0,0 +1,464 @@ +#include "include.h" +#include "ip.h" +#include "/sys/src/libmach/elf.h" + +int tftpupload(char *name, void *p, int len); + +extern ulong cpuentry; + +static uchar elfident[7] = { + '\177', 'E', 'L', 'F', '\1', '\1', '\1' +}; +static Ehdr ehdr, rehdr; +static Phdr *phdr; +static int curphdr; +static ulong curoff; +static ulong elftotal; + +static long (*swal)(long); +static ushort (*swab)(ushort); + +/* + * big-endian short + */ +ushort +beswab(ushort s) +{ + uchar *p; + + p = (uchar*)&s; + return (p[0]<<8) | p[1]; +} + +/* + * big-endian long + */ +long +beswal(long l) +{ + uchar *p; + + p = (uchar*)&l; + return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3]; +} + +/* + * little-endian short + */ +ushort +leswab(ushort s) +{ + uchar *p; + + p = (uchar*)&s; + return (p[1]<<8) | p[0]; +} + +/* + * little-endian long + */ +long +leswal(long l) +{ + uchar *p; + + p = (uchar*)&l; + return (p[3]<<24) | (p[2]<<16) | (p[1]<<8) | p[0]; +} + +/* + * Convert header to canonical form + */ +static void +hswal(long *lp, int n, long (*swap) (long)) +{ + while (n--) { + *lp = (*swap) (*lp); + lp++; + } +} + +static int +readehdr(Boot *b) +{ + int i; + + /* bitswap the header according to the DATA format */ + if(ehdr.ident[CLASS] != ELFCLASS32) { + print("bad ELF class - not 32 bit\n"); + return 0; + } + if(ehdr.ident[DATA] == ELFDATA2LSB) { + swab = leswab; + swal = leswal; + } else if(ehdr.ident[DATA] == ELFDATA2MSB) { + swab = beswab; + swal = beswal; + } else { + print("bad ELF encoding - not big or little endian\n"); + return 0; + } + memmove(&rehdr, &ehdr, sizeof(Ehdr)); + + ehdr.type = swab(ehdr.type); + ehdr.machine = swab(ehdr.machine); + ehdr.version = swal(ehdr.version); + ehdr.elfentry = swal(ehdr.elfentry); + ehdr.phoff = swal(ehdr.phoff); + ehdr.shoff = swal(ehdr.shoff); + ehdr.flags = swal(ehdr.flags); + ehdr.ehsize = swab(ehdr.ehsize); + ehdr.phentsize = swab(ehdr.phentsize); + ehdr.phnum = swab(ehdr.phnum); + ehdr.shentsize = swab(ehdr.shentsize); + ehdr.shnum = swab(ehdr.shnum); + ehdr.shstrndx = swab(ehdr.shstrndx); + if(ehdr.type != EXEC || ehdr.version != CURRENT) + return 0; + if(ehdr.phentsize != sizeof(Phdr)) + return 0; + + if(debug) + print("readehdr OK entry 0x%lux\n", ehdr.elfentry); + + curoff = sizeof(Ehdr); + i = ehdr.phoff+ehdr.phentsize*ehdr.phnum - curoff; + b->state = READPHDR; + b->bp = (char*)malloc(i); + b->wp = b->bp; + b->ep = b->wp + i; + phdr = (Phdr*)(b->bp + ehdr.phoff-sizeof(Ehdr)); + if(debug) + print("phdr..."); + + return 1; +} + +static int +nextphdr(Boot *b) +{ + Phdr *php; + ulong entry, offset; + char *paddr; + + if(debug) + print("readedata %d\n", curphdr); + + for(; curphdr < ehdr.phnum; curphdr++){ + php = phdr+curphdr; + if(php->type != LOAD) + continue; + offset = php->offset; + paddr = (char*)PADDR(php->paddr); + if(offset < curoff){ + /* + * Can't (be bothered to) rewind the + * input, it might be from tftp. If we + * did then we could boot FreeBSD kernels + * too maybe. + */ + return 0; + } + if(php->offset > curoff){ + b->state = READEPAD; + b->bp = (char*)malloc(offset - curoff); + b->wp = b->bp; + b->ep = b->wp + offset - curoff; + if(debug) + print("nextphdr %lud...\n", offset - curoff); + return 1; + } + b->state = READEDATA; + b->bp = paddr; + b->wp = b->bp; + b->ep = b->wp+php->filesz; + print("%ud+", php->filesz); + elftotal += php->filesz; + if(debug) + print("nextphdr %ud@0x%p\n", php->filesz, paddr); + + return 1; + } + + if(curphdr != 0){ + print("=%lud\n", elftotal); + b->state = TRYBOOT; + entry = ehdr.elfentry & ~0xF0000000; + PLLONG(b->exec.entry, entry); + return 1; + } + + return 0; +} + +static int +readepad(Boot *b) +{ + Phdr *php; + + php = phdr+curphdr; + if(debug) + print("readepad %d\n", curphdr); + curoff = php->offset; + + return nextphdr(b); +} + +static int +readedata(Boot *b) +{ + Phdr *php; + + php = phdr+curphdr; + if(debug) + print("readedata %d\n", curphdr); + if(php->filesz < php->memsz){ + print("%lud", php->memsz-php->filesz); + elftotal += php->memsz-php->filesz; + memset((char*)(PADDR(php->paddr)+php->filesz), 0, php->memsz-php->filesz); + } + curoff = php->offset+php->filesz; + curphdr++; + + return nextphdr(b); +} + +static int +readphdr(Boot *b) +{ + Phdr *php; + + php = phdr; + hswal((long*)php, ehdr.phentsize*ehdr.phnum/sizeof(long), swal); + if(debug) + print("phdr curoff %lud vaddr 0x%lux paddr 0x%lux\n", + curoff, php->vaddr, php->paddr); + + curoff = ehdr.phoff+ehdr.phentsize*ehdr.phnum; + curphdr = 0; + + return nextphdr(b); +} + +static ulong chksum, length; + +static void +sum(void *vp, int len) +{ + unsigned long *p; + + if (len % sizeof(int) != 0) { + print("sum: len %d not a multiple of word size\n", + len); + return; + } + p = vp; + len /= sizeof *p; + while (len-- > 0) + chksum += *p++; +} + +static int +addbytes(char **dbuf, char *edbuf, char **sbuf, char *esbuf) +{ + int n; + static ulong *start; + + n = edbuf - *dbuf; + if(n <= 0) + return 0; + if(n > esbuf - *sbuf) + n = esbuf - *sbuf; + if(n <= 0) + return -1; + + memmove(*dbuf, *sbuf, n); + coherence(); + + /* verify that the copy worked */ + if (memcmp(*dbuf, *sbuf, n) != 0) + panic("addbytes: memmove copied %d bytes wrong from %#p to %#p", + n, *sbuf, *dbuf); + *sbuf += n; + *dbuf += n; + return edbuf - *dbuf; +} + +int +bootpass(Boot *b, void *vbuf, int nbuf) +{ + char *buf, *ebuf; + Exec *ep; + ulong entry, data, text, bss; + + SET(text, data); + USED(text, data); + if(b->state == FAILED) + return FAIL; + + if(nbuf == 0) + goto Endofinput; + + buf = vbuf; + ebuf = buf+nbuf; + while(addbytes(&b->wp, b->ep, &buf, ebuf) == 0) { + switch(b->state) { + case INITKERNEL: + b->state = READEXEC; + b->bp = (char*)&b->exec; + b->wp = b->bp; + b->ep = b->bp+sizeof(Exec); + break; + case READEXEC: + ep = &b->exec; + if(GLLONG(ep->magic) == Q_MAGIC) { + b->state = READ9TEXT; + b->bp = (char*)PADDR(GLLONG(ep->entry)); + b->wp = b->bp; + b->ep = b->wp+GLLONG(ep->text); + print("%lud", GLLONG(ep->text)); + break; + } + + /* + * Check for ELF. + */ + if(memcmp(b->bp, elfident, 4) == 0){ + b->state = READEHDR; + b->bp = (char*)&ehdr; + b->wp = b->bp; + b->ep = b->wp + sizeof(Ehdr); + memmove(b->bp, &b->exec, sizeof(Exec)); + b->wp += sizeof(Exec); + print("elf..."); + break; + } + + print("bad kernel format\n"); + b->state = FAILED; + return FAIL; + + case READ9TEXT: + ep = &b->exec; + b->state = READ9DATA; + b->bp = (char*)UTROUND(PADDR(GLLONG(ep->entry)) + + GLLONG(ep->text)); + b->wp = b->bp; + b->ep = b->wp + GLLONG(ep->data); + { + /* + * fill the gap between text and first page + * of data. + */ + int wds; + ulong *dst = (ulong *)(PADDR(GLLONG(ep->entry))+ + GLLONG(ep->text)); + + for (wds = (ulong *)b->bp - dst; wds-- > 0; + dst++) + *dst = (uintptr)dst; + } + print("+%ld", GLLONG(ep->data)); + length = b->ep - (char *)PADDR(GLLONG(ep->entry)); + break; + + case READ9DATA: + ep = &b->exec; + bss = GLLONG(ep->bss); + print("+%ld=%ld\n", + bss, GLLONG(ep->text)+GLLONG(ep->data)+bss); + b->state = TRYBOOT; + return ENOUGH; + + case READEHDR: + if(!readehdr(b)){ + print("readehdr failed\n"); + b->state = FAILED; + return FAIL; + } + break; + + case READPHDR: + if(!readphdr(b)){ + b->state = FAILED; + return FAIL; + } + break; + + case READEPAD: + if(!readepad(b)){ + b->state = FAILED; + return FAIL; + } + break; + + case READEDATA: + if(!readedata(b)){ + b->state = FAILED; + return FAIL; + } + if(b->state == TRYBOOT) + return ENOUGH; + break; + + case TRYBOOT: + case READGZIP: + return ENOUGH; + + case READ9LOAD: + case INIT9LOAD: + panic("9load"); + + default: + panic("bootstate"); + } + } + return MORE; + + +Endofinput: + /* end of input */ + switch(b->state) { + case INITKERNEL: + case READEXEC: + case READ9TEXT: + case READ9DATA: + case READEHDR: + case READPHDR: + case READEPAD: + case READEDATA: + print("premature EOF\n"); + b->state = FAILED; + return FAIL; + + case TRYBOOT: + delay(100); + syncall(); + entry = GLLONG(b->exec.entry); + dcflush(PADDR(entry), 4*1024*1024); /* HACK */ + + sum((void *)PADDR(entry), length); + print("checksum: %#luX (on length %lud)\n", chksum, length); + + print("entry: 0x%lux\n", entry); + delay(20); + + cpuentry = entry; /* for second cpu's use */ + coherence(); + dcflush((uintptr)&cpuentry, sizeof cpuentry); + + warp9(PADDR(entry)); + + b->state = FAILED; + return FAIL; + + case INIT9LOAD: + case READ9LOAD: + panic("end 9load"); + + default: + panic("bootdone"); + } + b->state = FAILED; + return FAIL; +} diff -Nru /sys/src/boot/vt4/bootp.c /sys/src/boot/vt4/bootp.c --- /sys/src/boot/vt4/bootp.c Thu Jan 1 00:00:00 1970 +++ /sys/src/boot/vt4/bootp.c Fri Jun 7 00:00:00 2013 @@ -0,0 +1,779 @@ +#include "include.h" +#include "ip.h" +#include "fs.h" + +#define INIPATHLEN 64 + +typedef struct Pxether Pxether; +static struct Pxether { + Fs fs; + char ini[INIPATHLEN]; +} *pxether; + +extern int debug; +extern int debugload; +extern char *persist; + +uchar broadcast[Eaddrlen] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +}; + +static ushort tftpport = 5000; +static int Id = 1; +static int ctlrinuse; +static Netaddr myaddr; +static Netaddr server; + +typedef struct { + uchar header[4]; + uchar data[Segsize]; +} Tftp; +static Tftp *tftpbp; + +static void +hnputs(uchar *ptr, ushort val) +{ + ptr[0] = val>>8; + ptr[1] = val; +} + +static void +hnputl(uchar *ptr, ulong val) +{ + ptr[0] = val>>24; + ptr[1] = val>>16; + ptr[2] = val>>8; + ptr[3] = val; +} + +static ulong +nhgetl(uchar *ptr) +{ + return ((ptr[0]<<24) | (ptr[1]<<16) | (ptr[2]<<8) | ptr[3]); +} + +static ushort +nhgets(uchar *ptr) +{ + return ((ptr[0]<<8) | ptr[1]); +} + +static short endian = 1; +static char* aendian = (char*)&endian; +#define LITTLE *aendian + +static ushort +ptcl_csum(void *a, int len) +{ + uchar *addr; + ulong t1, t2; + ulong losum, hisum, mdsum, x; + + addr = a; + losum = 0; + hisum = 0; + mdsum = 0; + + x = 0; + if((ulong)addr & 1) { + if(len) { + hisum += addr[0]; + len--; + addr++; + } + x = 1; + } + while(len >= 16) { + t1 = *(ushort*)(addr+0); + t2 = *(ushort*)(addr+2); mdsum += t1; + t1 = *(ushort*)(addr+4); mdsum += t2; + t2 = *(ushort*)(addr+6); mdsum += t1; + t1 = *(ushort*)(addr+8); mdsum += t2; + t2 = *(ushort*)(addr+10); mdsum += t1; + t1 = *(ushort*)(addr+12); mdsum += t2; + t2 = *(ushort*)(addr+14); mdsum += t1; + mdsum += t2; + len -= 16; + addr += 16; + } + while(len >= 2) { + mdsum += *(ushort*)addr; + len -= 2; + addr += 2; + } + if(x) { + if(len) + losum += addr[0]; + if(LITTLE) + losum += mdsum; + else + hisum += mdsum; + } else { + if(len) + hisum += addr[0]; + if(LITTLE) + hisum += mdsum; + else + losum += mdsum; + } + + losum += hisum >> 8; + losum += (hisum & 0xff) << 8; + while(hisum = losum>>16) + losum = hisum + (losum & 0xffff); + + return ~losum; +} + +static ushort +ip_csum(uchar *addr) +{ + int len; + ulong sum = 0; + + len = (addr[0]&0xf)<<2; + + while(len > 0) { + sum += addr[0]<<8 | addr[1] ; + len -= 2; + addr += 2; + } + + sum = (sum & 0xffff) + (sum >> 16); + sum = (sum & 0xffff) + (sum >> 16); + return (sum^0xffff); +} + +static void +udpsend(int ctlrno, Netaddr *a, void *data, int dlen) +{ + Udphdr *uh; + Etherhdr *ip; + Etherpkt pkt; + int len, ptcllen; + + uh = (Udphdr*)&pkt; + + memset(uh, 0, sizeof(Etherpkt)); + memmove(uh->udpcksum+sizeof(uh->udpcksum), data, dlen); + + /* + * UDP portion + */ + ptcllen = dlen + (UDP_HDRSIZE-UDP_PHDRSIZE); + uh->ttl = 0; + uh->udpproto = IP_UDPPROTO; + uh->frag[0] = 0; + uh->frag[1] = 0; + hnputs(uh->udpplen, ptcllen); + hnputl(uh->udpsrc, myaddr.ip); + hnputs(uh->udpsport, myaddr.port); + hnputl(uh->udpdst, a->ip); + hnputs(uh->udpdport, a->port); + hnputs(uh->udplen, ptcllen); + uh->udpcksum[0] = 0; + uh->udpcksum[1] = 0; + dlen = (dlen+1)&~1; + hnputs(uh->udpcksum, ptcl_csum(&uh->ttl, dlen+UDP_HDRSIZE)); + + /* + * IP portion + */ + ip = (Etherhdr*)&pkt; + len = UDP_EHSIZE+UDP_HDRSIZE+dlen; /* non-descriptive names */ + ip->vihl = IP_VER|IP_HLEN; + ip->tos = 0; + ip->ttl = 255; + hnputs(ip->length, len-ETHER_HDR); + hnputs(ip->id, Id++); + ip->frag[0] = 0; + ip->frag[1] = 0; + ip->cksum[0] = 0; + ip->cksum[1] = 0; + hnputs(ip->cksum, ip_csum(&ip->vihl)); + + /* + * Ethernet MAC portion + */ + hnputs(ip->type, ET_IP); + memmove(ip->d, a->ea, sizeof(ip->d)); + +if(debug) { + print("udpsend "); +} + /* + * if packet is too short, make it longer rather than relying + * on ethernet interface or lower layers to pad it. + */ + if (len < ETHERMINTU) + len = ETHERMINTU; + ethertxpkt(ctlrno, &pkt, len, Timeout); +} + +static void +nak(int ctlrno, Netaddr *a, int code, char *msg, int report) +{ + int n; + char buf[128]; + + buf[0] = 0; + buf[1] = Tftp_ERROR; + buf[2] = 0; + buf[3] = code; + strecpy(buf+4, buf + sizeof buf, msg); + n = strlen(msg) + 4 + 1; + udpsend(ctlrno, a, buf, n); + if(report) + print("\ntftp: error(%d): %s\n", code, msg); +} + +void +dump(void *vaddr, int words) +{ + ulong *addr; + + addr = vaddr; + while (words-- > 0) + print("%.8lux%c", *addr++, words % 8 == 0? '\n': ' '); +} + +static int +udprecv(int ctlrno, Netaddr *a, void *data, int dlen) +{ + int n, len; + ushort csm; + Udphdr *h; + ulong addr, timo; + Etherpkt pkt; + static int rxactive; + + if(rxactive == 0) + timo = 1000; + else + timo = Timeout; + timo += TK2MS(m->ticks); + while(timo > TK2MS(m->ticks)){ + n = etherrxpkt(ctlrno, &pkt, timo - TK2MS(m->ticks)); + if(n <= 0) + continue; + + h = (Udphdr*)&pkt; + if(debug) + print("udprecv %E to %E...\n", h->s, h->d); + + if(nhgets(h->type) != ET_IP) { + if(debug) + print("not ip..."); + continue; + } + + if(ip_csum(&h->vihl)) { + print("ip chksum error\n"); + continue; + } + if(h->vihl != (IP_VER|IP_HLEN)) { + print("ip bad vers/hlen\n"); + continue; + } + + if(h->udpproto != IP_UDPPROTO) { + if(debug) + print("not udp (%d)...", h->udpproto); + continue; + } + + if(debug) + print("okay udp..."); + + h->ttl = 0; + len = nhgets(h->udplen); + hnputs(h->udpplen, len); + + if(nhgets(h->udpcksum)) { + csm = ptcl_csum(&h->ttl, len+UDP_PHDRSIZE); + if(csm != 0) { + print("udp chksum error csum #%4ux len %d\n", + csm, n); + break; + } + } + + if(a->port != 0 && nhgets(h->udpsport) != a->port) { + if(debug) + print("udpport %ux not %ux\n", + nhgets(h->udpsport), a->port); + continue; + } + + addr = nhgetl(h->udpsrc); + if(a->ip != Bcastip && a->ip != addr) { + if(debug) + print("bad ip %lux not %lux\n", addr, a->ip); + continue; + } + + len -= UDP_HDRSIZE-UDP_PHDRSIZE; + if(len > dlen) { + print("udp: packet too big: %d > %d; from addr %E\n", + len, dlen, h->udpsrc); + continue; + } + + memmove(data, h->udpcksum+sizeof(h->udpcksum), len); + a->ip = addr; + a->port = nhgets(h->udpsport); + memmove(a->ea, pkt.s, sizeof(a->ea)); + + rxactive = 1; + return len; + } + + return 0; +} + +static int tftpblockno; + +/* + * format of a request packet, from the RFC: + * + 2 bytes string 1 byte string 1 byte + ------------------------------------------------ + | Opcode | Filename | 0 | Mode | 0 | + ------------------------------------------------ + */ +static int +tftpopen(int ctlrno, Netaddr *a, char *name, Tftp *tftp, int op) +{ + int i, len, rlen, oport; + char *end; + static char buf[Segsize+2]; /* reduce stack use */ + + ctlrinuse = ctlrno; + buf[0] = 0; + buf[1] = op; + end = seprint(buf+2, buf + sizeof buf, "%s", name) + 1; + end = seprint(end, buf + sizeof buf, "octet") + 1; + len = end - buf; + + oport = a->port; + for(i = 0; i < 5; i++){ + a->port = oport; + udpsend(ctlrno, a, buf, len); + a->port = 0; + if((rlen = udprecv(ctlrno, a, tftp, sizeof(Tftp))) < sizeof(tftp->header)) + continue; + + switch((tftp->header[0]<<8)|tftp->header[1]){ + case Tftp_ERROR: + print("tftpopen: error (%d): %s\n", + (tftp->header[2]<<8)|tftp->header[3], + (char*)tftp->data); + return -1; + case Tftp_DATA: + /* this should only happen when opening to read */ + tftpblockno = 1; + len = (tftp->header[2]<<8)|tftp->header[3]; + if(len != tftpblockno){ + print("tftpopen: block error: %d\n", len); + nak(ctlrno, a, 1, "block error", 0); + return -1; + } + rlen -= sizeof(tftp->header); + if(rlen < Segsize){ + /* ACK last block now, in case we don't later */ + buf[0] = 0; + buf[1] = Tftp_ACK; + buf[2] = tftpblockno>>8; + buf[3] = tftpblockno; + udpsend(ctlrno, a, buf, sizeof(tftp->header)); + } + return rlen; + case Tftp_ACK: + /* this should only happen when opening to write */ + len = (tftp->header[2]<<8)|tftp->header[3]; + if(len != 0){ + print("tftpopen: block # error: %d != 0\n", + len); + nak(ctlrno, a, 1, "block # error", 0); + return -1; + } + return 0; + } + } + + print("tftpopen: failed to connect to server\n"); + return -1; +} + +static int +tftpread(int ctlrno, Netaddr *a, Tftp *tftp, int dlen) +{ + uchar buf[4]; + int try, blockno, len; + + dlen += sizeof(tftp->header); + + for(try = 0; try < 10; try++) { + buf[0] = 0; + buf[1] = Tftp_ACK; + buf[2] = tftpblockno>>8; + buf[3] = tftpblockno; + + udpsend(ctlrno, a, buf, sizeof(buf)); + len = udprecv(ctlrno, a, tftp, dlen); + if(len <= sizeof(tftp->header)){ + if(debug) + print("tftpread: too short %d <= %d\n", + len, sizeof(tftp->header)); + continue; + } + blockno = (tftp->header[2]<<8)|tftp->header[3]; + if(blockno <= tftpblockno){ + if(debug) + print("tftpread: blkno %d <= %d\n", + blockno, tftpblockno); + continue; + } + + if(blockno == tftpblockno+1) { + tftpblockno++; + if(len < dlen) { /* last packet; send final ack */ + tftpblockno++; + buf[0] = 0; + buf[1] = Tftp_ACK; + buf[2] = tftpblockno>>8; + buf[3] = tftpblockno; + udpsend(ctlrno, a, buf, sizeof(buf)); + } + return len-sizeof(tftp->header); + } + print("tftpread: block error: %d, expected %d\n", + blockno, tftpblockno+1); + } + + return -1; +} + +static int +bootpopen(int ctlrno, char *file, Bootp *rep, int dotftpopen) +{ + Bootp req; + int i, n; + uchar *ea; + char name[128], *filename, *sysname; + + if (debugload) + print("bootpopen: ether%d!%s...", ctlrno, file); + if((ea = etheraddr(ctlrno)) == 0){ + print("invalid ctlrno %d\n", ctlrno); + return -1; + } + + filename = 0; + sysname = 0; + if(file && *file){ + strecpy(name, name + sizeof name, file); + if(filename = strchr(name, '!')){ + sysname = name; + *filename++ = 0; + } + else + filename = name; + } + + memset(&req, 0, sizeof(req)); + req.op = Bootrequest; + req.htype = 1; /* ethernet */ + req.hlen = Eaddrlen; /* ethernet */ + memmove(req.chaddr, ea, Eaddrlen); + if(filename != nil) + strncpy(req.file, filename, sizeof(req.file)); + if(sysname != nil) + strncpy(req.sname, sysname, sizeof(req.sname)); + + myaddr.ip = 0; + myaddr.port = BPportsrc; + memmove(myaddr.ea, ea, Eaddrlen); + + etherrxflush(ctlrno); + for(i = 0; i < 10; i++) { + server.ip = Bcastip; + server.port = BPportdst; + memmove(server.ea, broadcast, sizeof(server.ea)); + udpsend(ctlrno, &server, &req, sizeof(req)); + if(udprecv(ctlrno, &server, rep, sizeof(*rep)) <= 0) + continue; + if(memcmp(req.chaddr, rep->chaddr, Eaddrlen)) + continue; + if(rep->htype != 1 || rep->hlen != Eaddrlen) + continue; + if(sysname == 0 || strcmp(sysname, rep->sname) == 0) + break; + } + if(i >= 10) { + print("bootp on ether%d for %s timed out\n", ctlrno, file); + return -1; + } + + if(!dotftpopen) + return 0; + + if(filename == 0 || *filename == 0){ + if(strcmp(rep->file, "/386/9pxeload") == 0) + return -1; + filename = rep->file; + } + + if(rep->sname[0] != '\0') + print("%s ", rep->sname); + print("(%d.%d.%d.%d!%d): %s\n", + rep->siaddr[0], + rep->siaddr[1], + rep->siaddr[2], + rep->siaddr[3], + server.port, + filename); + + myaddr.ip = nhgetl(rep->yiaddr); + myaddr.port = tftpport++; + server.ip = nhgetl(rep->siaddr); + server.port = TFTPport; + + if((n = tftpopen(ctlrno, &server, filename, tftpbp, Tftp_READ)) < 0) + return -1; + + return n; +} + +int +bootpboot(int ctlrno, char *file, Boot *b) +{ + int n; + Bootp rep; + + if (tftpbp == nil) + tftpbp = malloc(sizeof *tftpbp); + if((n = bootpopen(ctlrno, file, &rep, 1)) < 0) + return -1; + + while(bootpass(b, tftpbp->data, n) == MORE){ + n = tftpread(ctlrno, &server, tftpbp, sizeof(tftpbp->data)); + if(n < sizeof(tftpbp->data)) + break; + } + + if(0 < n && n < sizeof(tftpbp->data)) /* got to end of file */ + bootpass(b, tftpbp->data, n); + else + nak(ctlrno, &server, 3, "ok", 0); /* tftpclose to abort transfer */ + bootpass(b, nil, 0); /* boot if possible */ + return -1; +} + +static vlong +pxediskseek(Fs*, vlong) +{ + return -1; +} + +static long +pxediskread(Fs*, void*, long) +{ + return -1; +} + +static long +pxeread(File* f, void* va, long len) +{ + int n; + Bootp rep; + char *p, *v; + + if (pxether == nil) + pxether = malloc(MaxEther * sizeof *pxether); + if((n = bootpopen(f->fs->dev, pxether[f->fs->dev].ini, &rep, 1)) < 0) + return -1; + + p = v = va; + while(n > 0) { + if((p-v)+n > len) + n = len - (p-v); + memmove(p, tftpbp->data, n); + p += n; + if(n != Segsize) + break; + if((n = tftpread(f->fs->dev, &server, tftpbp, sizeof(tftpbp->data))) < 0) + return -1; + } + return p-v; +} + +static int +pxewalk(File* f, char* name) +{ + Bootp rep; + char *ini; + + switch(f->walked){ + default: + return -1; + case 0: + if(strcmp(name, "cfg") == 0){ + f->walked = 1; + return 1; + } + break; + case 1: + if(strcmp(name, "pxe") == 0){ + f->walked = 2; + return 1; + } + break; + case 2: + if(strcmp(name, "%E") != 0) + break; + f->walked = 3; + + if(bootpopen(f->fs->dev, nil, &rep, 0) < 0) + return 0; + + if (pxether == nil) + pxether = malloc(MaxEther * sizeof *pxether); + ini = pxether[f->fs->dev].ini; + /* use our mac address instead of relying on a bootp answer */ + seprint(ini, ini+INIPATHLEN, "/cfg/pxe/%E", (uchar *)myaddr.ea); + f->path = ini; + + return 1; + } + return 0; +} + +void* +pxegetfspart(int ctlrno, char* part, int) +{ + Fs *fs; + + if(!pxe || strcmp(part, "*") != 0 || ctlrno >= MaxEther || + iniread && getconf("*pxeini") != nil) + return nil; + + if (pxether == nil) + pxether = malloc(MaxEther * sizeof *pxether); + fs = &pxether[ctlrno].fs; + fs->dev = ctlrno; + fs->diskread = pxediskread; + fs->diskseek = pxediskseek; + + fs->read = pxeread; + fs->walk = pxewalk; + + fs->root.fs = fs; + fs->root.walked = 0; + + return fs; +} + +/* + * tftp upload, for memory dumps and the like. + */ + +void +sendfile(int ctlrno, Netaddr *a, void *p, int len, char *name) +{ + int ackblock, block, ret, rexmit, rlen, n, txtry, rxl; + short op; + char *mem, *emem; + static uchar ack[1024], buf[Segsize+4]; /* reduce stack use */ + + block = 0; + rexmit = 0; + n = 0; + mem = p; + emem = mem + len; + for(txtry = 0; txtry < 10;) { + if(rexmit == 0) { + block++; + buf[0] = 0; + buf[1] = Tftp_DATA; + buf[2] = block>>8; + buf[3] = block; + if (mem < emem) { + if (emem - mem < Segsize) + n = emem - mem; + else + n = Segsize; + memmove(buf+4, mem, n); + mem += n; + } else + n = 0; + txtry = 0; + } else { + print("rexmit %d bytes to %s:%d\n", 4+n, name, block); + txtry++; + } + + /* write buf to network */ + udpsend(ctlrno, a, buf, 4+n); + ret = 4+n; + + for(rxl = 0; rxl < 10; rxl++) { + rexmit = 0; + /* read ack from network */ + memset(ack, 0, 32); + rlen = udprecv(ctlrno, a, ack, sizeof ack); + if(rlen < sizeof tftpbp->header) { + rexmit = 1; + print("reply too small\n"); + break; + } + op = ack[0]<<8 | ack[1]; + if(op == Tftp_ERROR) { + print("sendfile: tftp error\n"); + break; + } + if (op != Tftp_ACK) { + print("expected ACK!\n"); + continue; + } + ackblock = ack[2]<<8 | ack[3]; + if(ackblock == block) + break; + else if(ackblock == 0xffff) { + rexmit = 1; + break; + } else + print("ack not for last block sent, " + "awaiting another\n"); + } + if (rxl >= 10) + print("never got ack for block %d\n", block); + if(ret != Segsize+4 && rexmit == 0) { + print(" done.\n"); + break; + } + if (0 && rexmit == 0) + print("."); + } + if (txtry >= 5) + print("too many rexmits\n"); +} + +int +tftpupload(char *name, void *p, int len) +{ + int n; + + if (tftpbp == nil) + tftpbp = malloc(sizeof *tftpbp); + + /* assume myaddr and server are still set from downloading */ + myaddr.port = tftpport++; + server.port = TFTPport; + + n = tftpopen(ctlrinuse, &server, name, tftpbp, Tftp_WRITE); + if(n < 0) + return -1; + sendfile(ctlrinuse, &server, p, len, name); + return 0; +} diff -Nru /sys/src/boot/vt4/clock.c /sys/src/boot/vt4/clock.c --- /sys/src/boot/vt4/clock.c Thu Jan 1 00:00:00 1970 +++ /sys/src/boot/vt4/clock.c Fri Jun 7 00:00:00 2013 @@ -0,0 +1,144 @@ +/* virtex[45] ppc4xx clock */ +#include "include.h" + +uvlong clockintrs; + +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 */ + + Wp17= 0<<30, /* watchdog period (2^x clocks) */ + Wp21= 1<<30, + Wp25= 2<<30, + Wp29= 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 */ + Fit9= 0<<24, /* fit period (2^x clocks) */ + Fit13= 1<<24, + Fit17= 2<<24, + Fit21= 3<<24, + Fie= 1<<23, /* fit interrupt enable */ + Are= 1<<22, /* auto reload enable */ +}; + +void +prcpuid(void) +{ + ulong pvr; + static char xilinx[] = "Xilinx "; + static char ppc[] = "PowerPC"; + + pvr = getpvr(); + m->cputype = pvr >> 16; + print("cpu%d: %ldMHz %#lux (", m->machno, m->cpuhz/1000000, pvr); + switch (m->cputype) { + case 0x1291: case 0x4011: case 0x41f1: case 0x5091: case 0x5121: + print("%s 405", ppc); + break; + case 0x2001: /* 200 is Xilinx, 1 is ppc405 */ + print(xilinx); + switch (pvr & ~0xfff) { + case 0x20010000: + print("Virtex-II Pro %s 405", ppc); + break; + case 0x20011000: + print("Virtex 4 FX %s 405D5X2", ppc); + break; + default: + print("%s 405", ppc); + break; + } + break; + case 0x7ff2: + print(xilinx); + if ((pvr & ~0xf) == 0x7ff21910) + print("Virtex 5 FXT %s 440X5", ppc); + else + print("%s 440", ppc); + break; + default: + print(ppc); + break; + } + print(")\n"); +} + +void +clockinit(void) +{ + int s; + long x; + vlong now; + + s = splhi(); + m->clockgen = m->cpuhz = myhz; + m->delayloop = m->cpuhz/1000; /* initial estimate */ + do { + x = gettbl(); + delay(10); + x = gettbl() - x; + } while(x < 0); + + /* + * fix count + */ + assert(x != 0); + 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; +// print("initial PIT %ld\n", x); + putpit(x); + puttsr(~0); + puttcr(Pie|Are); + coherence(); + splx(s); + + now = m->fastclock; + x = 50000000UL; + while (now == m->fastclock && x-- > 0) + ; + if (now == m->fastclock) + print("clock is NOT ticking\n"); +} + +void +clockintr(Ureg *ureg) +{ + /* PIT was set to reload automatically */ + puttsr(~0); + m->fastclock++; + dcflush(PTR2UINT(&m->fastclock), sizeof m->fastclock); /* seems needed */ + clockintrs++; + dcflush(PTR2UINT(&clockintrs), sizeof clockintrs); /* seems needed */ + timerintr(ureg); +} diff -Nru /sys/src/boot/vt4/conf.c /sys/src/boot/vt4/conf.c --- /sys/src/boot/vt4/conf.c Thu Jan 1 00:00:00 1970 +++ /sys/src/boot/vt4/conf.c Fri Jun 7 00:00:00 2013 @@ -0,0 +1,483 @@ +#include "include.h" +#include "fs.h" + +static char *confname[MAXCONF]; +static char *confval[MAXCONF]; +static int nconf; + +extern char **ini; + +typedef struct { + char* name; + int start; + int end; +} Mblock; + +typedef struct { + char* tag; + Mblock* mb; +} Mitem; + +static Mblock mblock[MAXCONF]; +static int nmblock; +static Mitem mitem[MAXCONF]; +static int nmitem; +static char* mdefault; +static char mdefaultbuf[10]; +static int mtimeout; + +static char* +comma(char* line, char** residue) +{ + char *q, *r; + + if((q = strchr(line, ',')) != nil){ + *q++ = 0; + if(*q == ' ') + q++; + } + *residue = q; + + if((r = strchr(line, ' ')) != nil) + *r = 0; + + if(*line == ' ') + line++; + return line; +} + +static Mblock* +findblock(char* name, char** residue) +{ + int i; + char *p; + + p = comma(name, residue); + for(i = 0; i < nmblock; i++){ + if(strcmp(p, mblock[i].name) == 0) + return &mblock[i]; + } + return nil; +} + +static Mitem* +finditem(char* name, char** residue) +{ + int i; + char *p; + + p = comma(name, residue); + for(i = 0; i < nmitem; i++){ + if(strcmp(p, mitem[i].mb->name) == 0) + return &mitem[i]; + } + return nil; +} + +static void +parsemenu(char* str, char* scratch, int len) +{ + Mitem *mi; + Mblock *mb, *menu, *nmb; + char buf[20], *p, *q, *line[MAXCONF]; + int i, inblock, n, show; + + inblock = 0; + menu = nil; + memmove(scratch, str, len); + n = getfields(scratch, line, MAXCONF, '\n'); + if(n >= MAXCONF) + print("warning: possibly too many lines in plan9.ini\n"); + nmb = &mblock[nmblock]; + for(i = 0; i < n; i++){ + p = line[i]; + if(inblock && *p == '['){ + nmb->end = i; + if(strcmp(nmb->name, "menu") == 0) + menu = nmb; + nmblock++; + nmb++; + inblock = 0; + } + if(*p == '['){ + if(nmblock == 0 && i != 0){ + nmb->name = "common"; + nmb->start = 0; + nmb->end = i; + nmblock++; + nmb++; + } + q = strchr(p+1, ']'); + if(q == nil || *(q+1) != 0){ + print("malformed menu block header - %s\n", p); + return; + } + *q = 0; + nmb->name = p+1; + nmb->start = i+1; + inblock = 1; + } + } + + if(inblock){ + (nmb++)->end = i; + nmblock++; + } + if(menu == nil) + return; + if(nmblock < 2){ + print("incomplete menu specification\n"); + return; + } + + for(i = menu->start; i < menu->end; i++){ + p = line[i]; + if(cistrncmp(p, "menuitem=", 9) == 0){ + p += 9; + if((mb = findblock(p, &q)) == nil){ + print("no block for menuitem %s\n", p); + return; + } + if(q != nil) + mitem[nmitem].tag = q; + else + mitem[nmitem].tag = mb->name; + mitem[nmitem].mb = mb; + nmitem++; + } + else if(cistrncmp(p, "menudefault=", 12) == 0){ + p += 12; + if((mi = finditem(p, &q)) == nil){ + print("no item for menudefault %s\n", p); + return; + } + if(q != nil) + mtimeout = strtol(q, 0, 0); + seprint(mdefaultbuf, mdefaultbuf + sizeof mdefaultbuf, + "%ld", mi-mitem+1); + mdefault = mdefaultbuf; + } + else if(cistrncmp(p, "menuconsole=", 12) == 0){ + p += 12; + p = comma(p, &q); + consinit(p, q); + } + else{ + print("invalid line in [menu] block - %s\n", p); + return; + } + } + +again: + print("\nPlan 9 Startup Menu:\n====================\n"); + for(i = 0; i < nmitem; i++) + print(" %d. %s\n", i+1, mitem[i].tag); + for(;;){ + getstr("Selection", buf, sizeof(buf), mdefault, mtimeout); + mtimeout = 0; + i = strtol(buf, &p, 0)-1; + if(i < 0 || i >= nmitem) + goto again; + switch(*p){ + case 'p': + case 'P': + show = 1; + print("\n"); + break; + case 0: + show = 0; + break; + default: + continue; + + } + mi = &mitem[i]; + + p = seprint(str, str + len, "menuitem=%s\n", mi->mb->name); + for(i = 0; i < nmblock; i++){ + mb = &mblock[i]; + if(mi->mb != mb && cistrcmp(mb->name, "common") != 0) + continue; + for(n = mb->start; n < mb->end; n++) + p = seprint(p, str + len, "%s\n", line[n]); + } + + if(show){ + for(q = str; q < p; q += i){ + if((i = print(q)) <= 0) + break; + } + goto again; + } + break; + } + print("\n"); +} + +char* +getconf(char *name) +{ + int i, n, nmatch; + char buf[20]; + + nmatch = 0; + for(i = 0; i < nconf; i++) + if(cistrcmp(confname[i], name) == 0) + nmatch++; + + switch(nmatch) { + default: + print("\n"); + nmatch = 0; + for(i = 0; i < nconf; i++) + if(cistrcmp(confname[i], name) == 0) + print("%d. %s\n", ++nmatch, confval[i]); + print("%d. none of the above\n", ++nmatch); + do { + getstr(name, buf, sizeof(buf), nil, 0); + n = strtoul(buf, 0, 10); + } while(n < 1 || n > nmatch); + + for(i = 0; i < nconf; i++) + if(cistrcmp(confname[i], name) == 0) + if(--n == 0) + return confval[i]; + break; + + case 1: + for(i = 0; i < nconf; i++) + if(cistrcmp(confname[i], name) == 0) + return confval[i]; + break; + + case 0: + break; + } + return nil; +} + +void +addconf(char *fmt, ...) +{ + va_list arg; + + va_start(arg, fmt); + vseprint(BOOTARGS+strlen(BOOTARGS), BOOTARGS+BOOTARGSLEN, fmt, arg); + va_end(arg); +} + +void +changeconf(char *fmt, ...) +{ + va_list arg; + char *p, *q, pref[20], buf[128]; + + va_start(arg, fmt); + vseprint(buf, buf+sizeof buf, fmt, arg); + va_end(arg); + strncpy(pref+1, buf, 19); + pref[19] = '\0'; + if(p = strchr(pref, '=')) + *(p+1) = '\0'; + else + print("warning: did not change %s in plan9.ini\n", buf); + + /* find old line by looking for \nwhat= */ + pref[0] = '\n'; + if(strncmp(BOOTARGS, pref+1, strlen(pref+1)) == 0) + p = BOOTARGS; + else if(p = strstr(BOOTARGS, pref)) + p++; + else + p = nil; + + /* move rest of args up, deleting what= line. */ + if(p != nil && (q = strchr(p, '\n')) != nil) + memmove(p, q+1, strlen(q+1)+1); + + /* add replacement to end */ + addconf("%s", buf); +} + +/* + * read configuration file + */ +static char inibuf[BOOTARGSLEN]; +static char id[8] = "ZORT 0\r\n"; + +int +dotini(Fs *fs) +{ + File rc; + int blankline, i, incomment, inspace, n; + char *cp, *p, *q, *line[MAXCONF]; + + if(fswalk(fs, *ini, &rc) <= 0) + return -1; + + cp = inibuf; + *cp = 0; + n = fsread(&rc, cp, BOOTARGSLEN-1); + if(n <= 0) + return -1; + + cp[n] = 0; + + /* + * Strip out '\r', change '\t' -> ' '. + * Change runs of spaces into single spaces. + * Strip out trailing spaces, blank lines. + * + * We do this before we make the copy so that if we + * need to change the copy, it is already fairly clean. + * The main need is in the case when plan9.ini has been + * padded with lots of trailing spaces, as is the case + * for those created during a distribution install. + */ + p = cp; + blankline = 1; + incomment = inspace = 0; + for(q = cp; *q; q++){ + if(*q == '\r') + continue; + if(*q == '\t') + *q = ' '; + if(*q == ' '){ + inspace = 1; + continue; + } + if(*q == '\n'){ + if(!blankline){ + if(!incomment) + *p++ = '\n'; + blankline = 1; + } + incomment = inspace = 0; + continue; + } + if(inspace){ + if(!blankline && !incomment) + *p++ = ' '; + inspace = 0; + } + if(blankline && *q == '#') + incomment = 1; + blankline = 0; + if(!incomment) + *p++ = *q; + } + if(p > cp && p[-1] != '\n') + *p++ = '\n'; + *p++ = 0; + n = p-cp; + + parsemenu(cp, BOOTARGS, n); + + /* + * Keep a copy. + * We could change this to pass the parsed strings + * to the booted programme instead of the raw + * string, then it only gets done once. + */ + if(strncmp(cp, id, sizeof(id))){ + memmove(BOOTARGS, id, sizeof(id)); + if(n+1+sizeof(id) >= BOOTARGSLEN) + n -= sizeof(id); + memmove(BOOTARGS+sizeof(id), cp, n+1); + } + else + memmove(BOOTARGS, cp, n+1); + + n = getfields(cp, line, MAXCONF, '\n'); + for(i = 0; i < n; i++){ + cp = strchr(line[i], '='); + if(cp == 0) + continue; + *cp++ = 0; + if(cp - line[i] >= NAMELEN+1) + *(line[i]+NAMELEN-1) = 0; + confname[nconf] = line[i]; + confval[nconf] = cp; + nconf++; + } + return 0; +} + +static int +parseether(uchar *to, char *from) +{ + char nip[4]; + char *p; + int i; + + p = from; + while(*p == ' ') + ++p; + for(i = 0; i < 6; i++){ + if(*p == 0) + return -1; + nip[0] = *p++; + if(*p == 0) + return -1; + nip[1] = *p++; + nip[2] = 0; + to[i] = strtoul(nip, 0, 16); + if(*p == ':') + p++; + } + return 0; +} + +int +isaconfig(char *class, int ctlrno, ISAConf *isa) +{ + char cc[NAMELEN], *p, *q, *r; + int n; + + seprint(cc, cc + sizeof cc, "%s%d", class, ctlrno); + for(n = 0; n < nconf; n++){ + if(cistrncmp(confname[n], cc, NAMELEN)) + continue; + isa->nopt = 0; + p = confval[n]; + while(*p){ + while(*p == ' ' || *p == '\t') + p++; + if(*p == '\0') + break; + if(cistrncmp(p, "type=", 5) == 0){ + p += 5; + for(q = isa->type; q < &isa->type[NAMELEN-1]; q++){ + if(*p == '\0' || *p == ' ' || *p == '\t') + break; + *q = *p++; + } + *q = '\0'; + } + else if(cistrncmp(p, "port=", 5) == 0) + isa->port = strtoul(p+5, &p, 0); + else if(cistrncmp(p, "mem=", 4) == 0) + isa->mem = strtoul(p+4, &p, 0); + else if(cistrncmp(p, "size=", 5) == 0) + isa->size = strtoul(p+5, &p, 0); + else if(cistrncmp(p, "ea=", 3) == 0){ + if(parseether(isa->ea, p+3) == -1) + memset(isa->ea, 0, 6); + } + else if(isa->nopt < NISAOPT){ + r = isa->opt[isa->nopt]; + while(*p && *p != ' ' && *p != '\t'){ + *r++ = *p++; + if(r-isa->opt[isa->nopt] >= ISAOPTLEN-1) + break; + } + *r = '\0'; + isa->nopt++; + } + while(*p && *p != ' ' && *p != '\t') + p++; + } + return 1; + } + return 0; +} diff -Nru /sys/src/boot/vt4/console.c /sys/src/boot/vt4/console.c --- /sys/src/boot/vt4/console.c Thu Jan 1 00:00:00 1970 +++ /sys/src/boot/vt4/console.c Fri Jun 7 00:00:00 2013 @@ -0,0 +1,185 @@ +#include "include.h" + +#define uartputs vuartputs +#define uartgets vuartgets +#define uartputc vuartputc + +static int useuart = 1; + +int debug; + +void +kbdinit(void) +{ +} + +void +consinit(char* name, char* speed) +{ + int port; + + if(name == nil || cistrcmp(name, "cga") == 0) + return; + port = strtoul(name, 0, 0); + if(port < 0 || port > 1) + return; + USED(speed); + + uartputs("\n", 1); +} + +void +consdrain(void) +{ +// if(useuart) +// uartdrain(); +} + +static void +consputs(char* s, int n) +{ + if(useuart) + uartputs(s, n); +} + +void +warp86(char* s, ulong) +{ + if(s != nil) + print(s); + spllo(); + consdrain(); + print("Takes a licking and keeps on ticking...\n"); + splhi(); + for(;;) + ; +} + +static int +getline(char *buf, int size, int timeout) +{ + int c, i=0; +// ulong start; + char echo; + + USED(timeout); + for (;;) { +// start = m->ticks; +// do{ +// /* timeout seconds to first char */ +// if(timeout && ((m->ticks - start) > timeout*HZ)) +// return -2; +// c = consiq.getc(&consiq); +// }while(c == -1); + c = vuartgetc(); +// timeout = 0; + + if(c == '\r') + c = '\n'; /* turn carriage return into newline */ + if(c == '\177') + c = '\010'; /* turn delete into backspace */ + if(c == '\025') + echo = '\n'; /* echo ^U as a newline */ + else + echo = c; + consputs(&echo, 1); + + if(c == '\010'){ + if(i > 0) + i--; /* bs deletes last character */ + continue; + } + /* a newline ends a line */ + if (c == '\n') + break; + /* ^U wipes out the line */ + if (c =='\025') + return -1; + if(i == size) + return size; + buf[i++] = c; + } + buf[i] = 0; + return i; +} + +int +getstr(char *prompt, char *buf, int size, char *def, int timeout) +{ + int len, isdefault; + char pbuf[PRINTSIZE]; + + buf[0] = 0; + isdefault = (def && *def); + if(isdefault == 0){ + timeout = 0; + seprint(pbuf, pbuf + sizeof pbuf, "%s: ", prompt); + } + else if(timeout) + seprint(pbuf, pbuf + sizeof pbuf, "%s[default==%s (%ds timeout)]: ", + prompt, def, timeout); + else + seprint(pbuf, pbuf + sizeof pbuf, "%s[default==%s]: ", + prompt, def); + for (;;) { + print(pbuf); + consdrain(); + len = getline(buf, size, timeout); + switch(len){ + case 0: + /* RETURN */ + if(isdefault) + break; + continue; + case -1: + /* ^U typed */ + continue; + case -2: + /* timeout, use default */ + consputs("\n", 1); + len = 0; + break; + default: + break; + } + if(len >= size){ + print("line too long\n"); + continue; + } + break; + } + if(len == 0 && isdefault) + strecpy(buf, buf + size, def); + return 0; +} + +void +panic(char *fmt, ...) +{ + int n; + va_list arg; + char buf[PRINTSIZE]; + + strecpy(buf, buf + sizeof buf, "panic: "); + va_start(arg, fmt); + n = vseprint(buf+7, buf+sizeof(buf)-7, fmt, arg) - buf; + va_end(arg); + buf[n] = '\n'; + consputs(buf, n+1); + + if (securemem) { + n = qtmerrfmt(buf, sizeof buf); + consputs(buf, n+1); + } + +// splhi(); for(;;); + if(etherdetach) + etherdetach(); + +// consputs("\nPress almost any key to reset...", 32); + spllo(); +// while(consiq.getc(&consiq) == -1) +// ; + vuartgetc(); + warp86(nil, 0); +} diff -Nru /sys/src/boot/vt4/data.h /sys/src/boot/vt4/data.h --- /sys/src/boot/vt4/data.h Thu Jan 1 00:00:00 1970 +++ /sys/src/boot/vt4/data.h Fri Jun 7 00:00:00 2013 @@ -0,0 +1,232 @@ +enum { + PRINTSIZE = 256, +}; + +#define MS2NS(n) (((vlong)(n))*1000000LL) +#define TK2MS(x) ((x)*(1000/HZ)) + +#define MB (1024*1024) + +/* + * Where configuration info is left for the loaded programme. + * This will turn into a structure as more is done by the boot loader + * (e.g. why parse the .ini file twice?). + * There are 3584 bytes available at CONFADDR on the PC. + * + * The low-level boot routines in l.s leave data for us at CONFADDR, + * which we pick up before reading the plan9.ini file. + */ +#define BOOTLINELEN 64 +#define BOOTARGS ((char*)(CONFADDR+BOOTLINELEN)) +#define BOOTARGSLEN 1024 /* size reduction */ +#define MAXCONF 15 /* from 100; size reduction */ + +/* + * intc bits, as of 18 aug 2009. + * specific to rae's virtex4 design + * vanilla design defines Intuarttx. + */ +enum { + Bitllfifo, + Bittemac, + Bitdma, + Bitdma2, + Bituart, + Bitmiiphy, + Bitqtmmacfail, /* qtm only */ + Bitqtmdraminit, /* qtm only */ + + Intllfifo=1<wp - (s)->rp) + +enum { + Eaddrlen = 6, + /* next two exclude 4-byte ether CRC */ + ETHERMINTU = 60, /* minimum transmit size */ + ETHERMAXTU = 1514, /* maximum transmit size */ + ETHERHDRSIZE = 14, /* size of an ethernet header */ + + MaxEther = 1, /* from 6; size reduction */ +}; + +typedef struct { + uchar d[Eaddrlen]; + uchar s[Eaddrlen]; + uchar type[2]; + uchar data[1500]; + uchar crc[4]; +} Etherpkt; + +enum { /* returned by bootpass */ + MORE, ENOUGH, FAIL +}; +enum { + INITKERNEL, + READEXEC, + READ9TEXT, + READ9DATA, + READGZIP, + READEHDR, + READPHDR, + READEPAD, + READEDATA, + TRYBOOT, + INIT9LOAD, + READ9LOAD, + FAILED +}; + +struct Boot { + int state; + + Exec exec; + char *bp; /* base ptr */ + char *wp; /* write ptr */ + char *ep; /* end ptr */ +}; + +extern uvlong clockintrs; +extern int debug; +extern char *defaultpartition; +extern int iniread; +extern uvlong myhz; +extern int pxe; +extern int securemem; +extern int vga; diff -Nru /sys/src/boot/vt4/define.h /sys/src/boot/vt4/define.h --- /sys/src/boot/vt4/define.h Thu Jan 1 00:00:00 1970 +++ /sys/src/boot/vt4/define.h Fri Jun 7 00:00:00 2013 @@ -0,0 +1 @@ +#undef PARANOID diff -Nru /sys/src/boot/vt4/ether.c /sys/src/boot/vt4/ether.c --- /sys/src/boot/vt4/ether.c Thu Jan 1 00:00:00 1970 +++ /sys/src/boot/vt4/ether.c Fri Jun 7 00:00:00 2013 @@ -0,0 +1,251 @@ +#include "include.h" +#include "ip.h" + +static Ether *ether; + +int debug; + +int temacreset(Ether*); +int plbtemacreset(Ether*); +int isaconfig(char*, int, ISAConf*); + +typedef struct Ethercard Ethercard; +struct Ethercard { + char *type; + int (*reset)(Ether*); + int noprobe; +} ethercards[] = { + { "temac", temacreset, 0, }, + { 0, } +}; + +static void xetherdetach(void); + +int +etherinit(void) /* called from probe() */ +{ + Ether *ctlr; + int ctlrno, i, mask, n, x; + + fmtinstall('E', eipfmt); + fmtinstall('V', eipfmt); + + etherdetach = xetherdetach; + mask = 0; + ether = malloc(MaxEther * sizeof *ether); + for(ctlrno = 0; ctlrno < MaxEther; ctlrno++){ + ctlr = ðer[ctlrno]; + memset(ctlr, 0, sizeof(Ether)); +// if(isaconfig("ether", ctlrno, ctlr) == 0) +// continue; + + for(n = 0; ethercards[n].type; n++){ + Ethercard *ecp; + + ecp = ðercards[n]; + if (1) { + if(ecp->noprobe) + continue; + memset(ctlr, 0, sizeof(Ether)); +// strecpy(ctlr->type, &ctlr->type[NAMELEN], +// ecp->type); + } +// else if(cistrcmp(ecp->type, ctlr->type) != 0) +// continue; + ctlr->ctlrno = ctlrno; + + x = splhi(); + if((*ecp->reset)(ctlr)){ + splx(x); + continue; + } + + ctlr->state = 1; /* card found */ + mask |= 1<irq, ctlr->interrupt, ctlr); + intrenable(Inttemac, ctlr->interrupt); + + print("ether#%d: port 0x%lux", ctlr->ctlrno, ctlr->port); + if(ctlr->mem) + print(" addr 0x%luX", ctlr->mem & ~KZERO); + if(ctlr->size) + print(" size 0x%luX", ctlr->size); + print(": %E\n", ctlr->ea); + + if(ctlr->nrb == 0) + ctlr->nrb = Nrb; + ctlr->rb = ialloc(sizeof(RingBuf)*ctlr->nrb, 0); + if(ctlr->ntb == 0) + ctlr->ntb = Ntb; + ctlr->tb = ialloc(sizeof(RingBuf)*ctlr->ntb, 0); + + ctlr->rh = 0; + ctlr->ri = 0; + for(i = 0; i < ctlr->nrb; i++) + ctlr->rb[i].owner = Interface; + + ctlr->th = 0; + ctlr->ti = 0; + for(i = 0; i < ctlr->ntb; i++) + ctlr->tb[i].owner = Host; + + splx(x); + break; + } + } + + return mask; +} + +void +etherinitdev(int i, char *s) +{ + seprint(s, s + NAMELEN, "ether%d", i); +} + +void +etherprintdevs(int i) +{ + print(" ether%d", i); +} + +static Ether* +attach(int ctlrno) +{ + Ether *ctlr; + + if(ctlrno >= MaxEther || ether[ctlrno].state == 0) + return 0; + + ctlr = ðer[ctlrno]; + if(ctlr->state == 1){ /* card found? */ + ctlr->state = 2; /* attaching */ + (*ctlr->attach)(ctlr); + } + + return ctlr; +} + +static void +xetherdetach(void) +{ + Ether *ctlr; + int ctlrno, x; + + x = splhi(); + for(ctlrno = 0; ctlrno < MaxEther; ctlrno++){ + ctlr = ðer[ctlrno]; + if(ctlr->detach && ctlr->state != 0) /* found | attaching? */ + ctlr->detach(ctlr); + } + splx(x); +} + +uchar* +etheraddr(int ctlrno) +{ + Ether *ctlr; + + if((ctlr = attach(ctlrno)) == 0) + return 0; + + return ctlr->ea; +} + +/* wait for owner of RingBuf to change from `owner' */ +static int +wait(RingBuf* ring, uchar owner, int timo) +{ + ulong start; + + start = m->ticks; + while(TK2MS(m->ticks - start) < timo) + if(ring->owner != owner) + return 1; + return 0; +} + +int +etherrxpkt(int ctlrno, Etherpkt* pkt, int timo) +{ + int n; + Ether *ctlr; + RingBuf *ring; + + if((ctlr = attach(ctlrno)) == 0) + return 0; + + ring = &ctlr->rb[ctlr->rh]; + if(wait(ring, Interface, timo) == 0){ + if(debug) + print("ether%d: rx timeout\n", ctlrno); + return 0; + } + + n = ring->len; + memmove(pkt, ring->pkt, n); + coherence(); + ring->owner = Interface; + ctlr->rh = NEXT(ctlr->rh, ctlr->nrb); + + return n; +} + +int +etherrxflush(int ctlrno) +{ + int n; + Ether *ctlr; + RingBuf *ring; + + if((ctlr = attach(ctlrno)) == 0) + return 0; + + n = 0; + for(;;){ + ring = &ctlr->rb[ctlr->rh]; + if(wait(ring, Interface, 100) == 0) + break; + + ring->owner = Interface; + ctlr->rh = NEXT(ctlr->rh, ctlr->nrb); + n++; + } + + return n; +} + +int +ethertxpkt(int ctlrno, Etherpkt* pkt, int len, int) +{ + Ether *ctlr; + RingBuf *ring; + int s; + + if((ctlr = attach(ctlrno)) == 0) + return 0; + + ring = &ctlr->tb[ctlr->th]; + if(wait(ring, Interface, 1000) == 0){ + print("ether%d: tx buffer timeout\n", ctlrno); + return 0; + } + + memmove(pkt->s, ctlr->ea, Eaddrlen); + if(debug) + print("%E to %E...\n", pkt->s, pkt->d); + memmove(ring->pkt, pkt, len); + if(len < ETHERMINTU){ + memset(ring->pkt+len, 0, ETHERMINTU-len); + len = ETHERMINTU; + } + ring->len = len; + ring->owner = Interface; + ctlr->th = NEXT(ctlr->th, ctlr->ntb); + coherence(); + s = splhi(); + (*ctlr->transmit)(ctlr); + splx(s); + + return 1; +} diff -Nru /sys/src/boot/vt4/etherif.h /sys/src/boot/vt4/etherif.h --- /sys/src/boot/vt4/etherif.h Thu Jan 1 00:00:00 1970 +++ /sys/src/boot/vt4/etherif.h Fri Jun 7 00:00:00 2013 @@ -0,0 +1,68 @@ +typedef struct RingBuf { + uchar owner; + uchar unused; + ushort len; + uchar pkt[sizeof(Etherpkt)]; +} RingBuf; + +enum { + Host = 0, /* buffer owned by host */ + Interface = 1, /* buffer owned by card */ + + Nrb = 32, /* default number of receive buffers */ + Ntb = 8, /* default number of transmit buffers */ +}; + +/* + * a parsed .ini line + */ +#define ISAOPTLEN 32 +#define NISAOPT 8 +#define NAMELEN 28 + +typedef struct ISAConf { + char type[NAMELEN]; + ulong port; +// ulong irq; + ulong mem; + ulong size; + uchar ea[6]; + + int nopt; + char opt[NISAOPT][ISAOPTLEN]; +} ISAConf; + +#define CONFADDR (0x2200) /* above ppc vectors */ +#define BOOTLINE ((char*)CONFADDR) + +typedef struct Ether Ether; +struct Ether { + ISAConf; /* hardware info */ + ushort ctlrno; + ushort state; /* 0: unfound, 1: found, 2: attaching */ + + void (*attach)(Ether*); /* filled in by reset routine */ + void (*transmit)(Ether*); + int (*interrupt)(ulong bit); + void (*detach)(Ether*); + void *ctlr; + + ushort nrb; /* number of software receive buffers */ + ushort ntb; /* number of software transmit buffers */ + RingBuf *rb; /* software receive buffers */ + RingBuf *tb; /* software transmit buffers */ + + ushort rh; /* first receive buffer belonging to host */ + ushort ri; /* first receive buffer belonging to card */ + + ushort th; /* first transmit buffer belonging to host */ + ushort ti; /* first transmit buffer belonging to card */ + ushort tbusy; /* transmitter is busy */ + ushort mbps; /* zero means link down */ +}; + +extern void etherrloop(Ether*, Etherpkt*, long); +extern void addethercard(char*, int(*)(Ether*)); + +#define NEXT(x, l) (((x)+1)%(l)) +#define PREV(x, l) (((x) == 0) ? (l)-1: (x)-1) diff -Nru /sys/src/boot/vt4/ethertemac.c /sys/src/boot/vt4/ethertemac.c --- /sys/src/boot/vt4/ethertemac.c Thu Jan 1 00:00:00 1970 +++ /sys/src/boot/vt4/ethertemac.c Fri Jun 7 00:00:00 2013 @@ -0,0 +1,354 @@ +/* + * Xilinx Temacs Ethernet driver. + * It uses the Local Link FIFOs. + * There are two interfaces per Temacs controller. + * Half-duplex is not supported by hardware. + */ +#include "include.h" + +enum { + /* fixed by hardware */ + Nifcs = 2, + + /* tunable parameters; see below for more */ + Nrde = 64, + Ntde = 4, +}; +enum { /* directly-addressible registers' bits */ + /* raf register */ + Htrst = 1<<0, /* hard temac reset (both ifcs) */ + Mcstrej = 1<<1, /* reject received multicast dest addr */ + Bcstrej = 1<<2, /* reject received broadcast dest addr */ + + /* is, ip, ie register */ + Hardacscmplt = 1<<0, /* hard register access complete */ + Autoneg = 1<<1, /* auto-negotiation complete */ + Rxcmplt = 1<<2, /* receive complete */ + Rxrject = 1<<3, /* receive frame rejected */ + Rxfifoovr = 1<<4, /* receive fifo overrun */ + Txcmplt = 1<<5, /* transmit complete */ + Rxdcmlock = 1<<6, /* receive DCM lock (ready for use) */ + Mgtrdy = 1<<7, /* mgt ready (new in 1.01b) + + /* ctl register */ + Wen = 1<<15, /* write instead of read */ + + /* ctl register address codes; select other registers */ + Rcw0 = 0x200, /* receive configuration */ + Rcw1 = 0x240, + Tc = 0x280, /* tx config */ + Fcc = 0x2c0, /* flow control */ + Emmc = 0x300, /* ethernet mac mode config */ + Phyc = 0x320, /* rgmii/sgmii config */ + Mc = 0x340, /* mgmt config */ + Uaw0 = 0x380, /* unicast addr word 0 (low-order) */ + Uaw1 = 0x384, /* unicast addr word 1 (high-order) */ + Maw0 = 0x388, /* multicast addr word 0 (low) */ + Maw1 = 0x38c, /* multicast addr word 1 (high + more) */ + Afm = 0x390, /* addr filter mode */ + Tis = 0x3a0, /* intr status */ + Tie = 0x3a4, /* intr enable */ + Miimwd = 0x3b0, /* mii mgmt write data */ + Miimai = 0x3b4, /* mii mgmt access initiate */ + + /* rdy register */ + Fabrrr = 1<<0, /* fabric read ready */ + Miimrr = 1<<1, /* mii mgmt read ready */ + Miimwr = 1<<2, /* mii mgmt write ready */ + Afrr = 1<<3, /* addr filter read ready */ + Afwr = 1<<4, /* addr filter write ready */ + Cfgrr = 1<<5, /* config reg read ready */ + Cfgwr = 1<<6, /* config reg write ready */ + Hardacsrdy = 1<<16, /* hard reg access ready */ +}; +enum { /* indirectly-addressible registers' bits */ + /* Rcw1 register */ + Rst = 1<<31, /* reset */ + Jum = 1<<30, /* jumbo frame enable */ + Fcs = 1<<29, /* in-band fcs enable */ + Rx = 1<<28, /* rx enable */ + Vlan = 1<<27, /* vlan frame enable */ + Hd = 1<<26, /* half-duplex mode (must be 0) */ + Ltdis = 1<<25, /* length/type field valid check disable */ + + /* Tc register. same as Rcw1 but Rx->Tx, Ltdis->Ifg */ + Tx = Rx, /* tx enable */ + Ifg = Ltdis, /* inter-frame gap adjustment enable */ + + /* Fcc register */ + Fctx = 1<<30, /* tx flow control enable */ + Fcrx = 1<<29, /* rx flow control enable */ + + /* Emmc register */ + Linkspeed = 3<<30, /* field */ + Ls1000 = 2<<30, /* Gb */ + Ls100 = 1<<30, /* 100Mb */ + Ls10 = 0<<30, /* 10Mb */ + Rgmii = 1<<29, /* rgmii mode enable */ + Sgmii = 1<<28, /* sgmii mode enable */ + Gpcs = 1<<27, /* 1000base-x mode enable */ + Hostifen= 1<<26, /* host interface enable */ + Tx16 = 1<<25, /* tx 16-bit (vs 8-bit) data ifc enable (0) */ + Rx16 = 1<<24, /* rx 16-bit (vs 8-bit) data ifc enable (0) */ + + /* Phyc register. sgmii link speed is Emmc's Linkspeed. */ + Rgmiills = 3<<2, /* field */ + Rls1000 = 2<<2, /* Gb */ + Rls100 = 1<<2, /* 100Mb */ + Rls10 = 0<<2, /* 10Mb */ + Rgmiihd = 1<<1, /* half-duplex */ + Rgmiilink = 1<<0, /* rgmii link (is up) */ + + /* Mc register */ + Mdioen = 1<<6, /* mdio (mii mgmt) enable */ + + /* Maw1 register */ + Rnw = 1<<23, /* multicast addr table reg read (vs write) */ + Addr = 3<<16, /* field */ + + /* Afm register */ + Pm = 1<<31, /* promiscuous mode */ + + /* Tis, Tie register (*rst->*en) */ + Fabrrst = 1<<0, /* fabric read intr sts (read done) */ + Miimrst = 1<<1, /* mii mgmt read intr sts (read done) */ + Miimwst = 1<<2, /* mii mgmt write intr sts (write done) */ + Afrst = 1<<3, /* addr filter read intr sts (read done) */ + Afwst = 1<<4, /* addr filter write intr sts (write done) */ + Cfgrst = 1<<5, /* config read intr sts (read done) */ + Cfgwst = 1<<6, /* config write intr sts (write done) */ +}; + +enum { + /* tunable parameters */ + Defmbps = 1000, /* default Mb/s */ + Defls = Ls1000, /* must match Defmbps */ +}; + +typedef struct Temacsw Temacsw; +typedef struct Temacregs Temacregs; +struct Temacregs { + ulong raf; /* reset & addr filter */ + ulong tpf; /* tx pause frame */ + ulong ifgp; /* tx inter-frame gap adjustment */ + ulong is; /* intr status */ + ulong ip; /* intr pending */ + ulong ie; /* intr enable */ + ulong pad[2]; + + ulong msw; /* msw data; shared by ifcs */ + ulong lsw; /* lsw data; shared */ + ulong ctl; /* control; shared */ + ulong rdy; /* ready status */ + ulong pad2[4]; +}; +struct Temacsw { + Temacregs *regs; +}; + +extern uchar mymac[Eaddrlen]; + +static Ether *ethers[1]; /* only first ether is connected to a fifo */ +static Lock shreglck; /* protects shared registers */ + +static void transmit(Ether *ether); + +static void +getready(Temacregs *trp) +{ + while ((trp->rdy & Hardacsrdy) == 0) + ; +} + +static ulong +rdindir(Temacregs *trp, unsigned code) +{ + ulong val; + + ilock(&shreglck); + getready(trp); + trp->ctl = code; + coherence(); + + getready(trp); + val = trp->lsw; + iunlock(&shreglck); + return val; +} + +static int +wrindir(Temacregs *trp, unsigned code, ulong val) +{ + ilock(&shreglck); + getready(trp); + trp->lsw = val; + coherence(); + trp->ctl = Wen | code; + coherence(); + + getready(trp); + iunlock(&shreglck); + return 0; +} + +static int +interrupt(ulong bit) +{ + int e, r, sts; + Ether *ether; + Temacsw *ctlr; + + r = 0; + for (e = 0; e < MaxEther; e++) { + ether = ethers[e]; + if (ether == nil) + continue; + ctlr = ether->ctlr; + sts = ctlr->regs->is; + if (sts) + r = 1; + ctlr->regs->is = sts; /* extinguish intr source */ + coherence(); + sts &= ~(Rxcmplt | Txcmplt | Rxdcmlock | Mgtrdy); + if (sts) + iprint("ethertemac: sts %#ux\n", sts); + } + if (r) + intrack(bit); + return r; +} + +static void +reset(Ether *ether) +{ + Temacsw *ctlr; + Temacregs *trp; + + ctlr = ether->ctlr; + trp = ctlr->regs; + trp->ie = 0; + coherence(); + /* don't use raf to reset: that resets both interfaces */ + wrindir(trp, Tc, Rst); + while (rdindir(trp, Tc) & Rst) + ; + wrindir(trp, Rcw1, Rst); + while (rdindir(trp, Rcw1) & Rst) + ; + llfiforeset(); +} + +static void +attach(Ether *) +{ +} + +static void +transmit(Ether *ether) +{ + RingBuf *tb; + + if (ether->tbusy) + return; + tb = ðer->tb[ether->ti]; + if (tb->owner != Interface) + return; + llfifotransmit(tb->pkt, tb->len); + coherence(); + tb->owner = Host; + coherence(); + ether->ti = NEXT(ether->ti, ether->ntb); + coherence(); +} + +static void +detach(Ether *ether) +{ + reset(ether); +} + +int +temacreset(Ether* ether) +{ + int i; + ulong ealo, eahi; + uvlong ea; + Temacsw *ctlr; + Temacregs *trp; + + if ((unsigned)ether->ctlrno >= nelem(ethers) || ethers[ether->ctlrno]) + return -1; /* already probed & found */ + trp = (Temacregs *)Temac + ether->ctlrno; + if (probeaddr((uintptr)trp) < 0) + return -1; + + ethers[ether->ctlrno] = ether; + ether->ctlr = ctlr = malloc(sizeof *ctlr); + ctlr->regs = trp; + + /* + * Determine media. + */ + ether->mbps = Defmbps; +// ether->mbps = media(ether, 1); + + /* + * Initialise descriptor rings, ethernet address. + */ + ether->nrb = Nrde; + ether->ntb = Ntde; + ether->rb = malloc(Nrde * sizeof(RingBuf)); + ether->tb = malloc(Ntde * sizeof(RingBuf)); + ether->port = Temac; + + reset(ether); + delay(1); + + llfifoinit(ether); + + wrindir(trp, Mc, Mdioen | 29); /* 29 is divisor; see p.47 of ds537 */ + delay(100); /* guess */ + + /* + * mac addr is stored little-endian in longs in Uaw[01]. + * default address is rubbish. + */ + memmove(ether->ea, mymac, Eaddrlen); + ea = 0; + for (i = 0; i < Eaddrlen; i++) + ea |= (uvlong)mymac[i] << (i * 8); + wrindir(trp, Uaw0, (ulong)ea); + wrindir(trp, Uaw1, (ulong)(ea >> 32)); + ealo = rdindir(trp, Uaw0); + eahi = rdindir(trp, Uaw1) & 0xffff; + if (ealo != (ulong)ea || eahi != (ulong)(ea >> 32)) + panic("temac mac address wouldn't set, got %lux %lux", + eahi, ealo); + + /* + * admit broadcast packets too + */ + wrindir(trp, Maw0, ~0ul); + wrindir(trp, Maw1, 0xffff); /* write to mat reg 0 */ + + wrindir(trp, Afm, 0); /* not promiscuous */ + wrindir(trp, Tc, Tx); + wrindir(trp, Emmc, Defls); + +/* intrenable(Inttemac, interrupt); /* done by ether.c */ + trp->ie = Rxrject | Rxfifoovr; /* just errors */ + coherence(); + + wrindir(trp, Tc, Tx); + wrindir(trp, Rcw1, Rx); + + /* + * Linkage to the generic ethernet driver. + */ + ether->attach = attach; + ether->transmit = transmit; + ether->interrupt = interrupt; + ether->detach = detach; + + return 0; +} diff -Nru /sys/src/boot/vt4/fakeqtm.c /sys/src/boot/vt4/fakeqtm.c --- /sys/src/boot/vt4/fakeqtm.c Thu Jan 1 00:00:00 1970 +++ /sys/src/boot/vt4/fakeqtm.c Fri Jun 7 00:00:00 2013 @@ -0,0 +1,23 @@ +#include "include.h" + +int +qtmerrfmt(char *, int) +{ + return 0; +} + +void +qtmerrtest(char *) +{ +} + +void +qtmerrtestaddr(ulong) +{ +} + +int +qtmmemreset(void) +{ + return 0; +} diff -Nru /sys/src/boot/vt4/fs.c /sys/src/boot/vt4/fs.c --- /sys/src/boot/vt4/fs.c Thu Jan 1 00:00:00 1970 +++ /sys/src/boot/vt4/fs.c Fri Jun 7 00:00:00 2013 @@ -0,0 +1,94 @@ +#include "include.h" +#include "fs.h" + +/* + * grab next element from a path, return the pointer to unprocessed portion of + * path. + */ +char * +nextelem(char *path, char *elem) +{ + int i; + + while(*path == '/') + path++; + if(*path==0 || *path==' ') + return 0; + for(i=0; *path!='\0' && *path!='/' && *path!=' '; i++){ + if(i==NAMELEN){ + print("name component too long\n"); + return 0; + } + *elem++ = *path++; + } + *elem = '\0'; + return path; +} + +int +fswalk(Fs *fs, char *path, File *f) +{ + char element[NAMELEN]; + + *f = fs->root; + if(BADPTR(fs->walk)) + panic("fswalk bad pointer fs->walk"); + + f->path = path; + while(path = nextelem(path, element)){ + switch(fs->walk(f, element)){ + case -1: + return -1; + case 0: + return 0; + } + } + return 1; +} + +enum { + Bufsize = 8192, +}; + +/* + * boot + */ +int +fsboot(Fs *fs, char *path, Boot *b) +{ + File file; + long n; + static char *buf; + + if (buf == nil) + buf = malloc(Bufsize + 1); + switch(fswalk(fs, path, &file)){ + case -1: + print("error walking to %s\n", path); + return -1; + case 0: + print("%s not found\n", path); + return -1; + case 1: + print("found %s\n", path); + break; + } + + while((n = fsread(&file, buf, Bufsize)) > 0) { + if(bootpass(b, buf, n) != MORE) + break; + } + + bootpass(b, nil, 0); /* tries boot */ + return -1; +} + +int +fsread(File *file, void *a, long n) +{ + if(BADPTR(file->fs)) + panic("bad pointer file->fs in fsread"); + if(BADPTR(file->fs->read)) + panic("bad pointer file->fs->read in fsread"); + return file->fs->read(file, a, n); +} diff -Nru /sys/src/boot/vt4/fs.h /sys/src/boot/vt4/fs.h --- /sys/src/boot/vt4/fs.h Thu Jan 1 00:00:00 1970 +++ /sys/src/boot/vt4/fs.h Fri Jun 7 00:00:00 2013 @@ -0,0 +1,22 @@ +struct File{ + int walked; + Fs *fs; + char *path; +}; + +struct Fs{ + int dev; /* device id */ + long (*diskread)(Fs*, void*, long); /* disk read routine */ + vlong (*diskseek)(Fs*, vlong); /* disk seek routine */ + long (*read)(File*, void*, long); + int (*walk)(File*, char*); + File root; +}; + +extern int chatty; +extern int dotini(Fs*); +extern int fswalk(Fs*, char*, File*); +extern int fsread(File*, void*, long); +extern int fsboot(Fs*, char*, Boot*); + +#define BADPTR(x) (0 && (ulong)x < 0x80000000) diff -Nru /sys/src/boot/vt4/include.h /sys/src/boot/vt4/include.h --- /sys/src/boot/vt4/include.h Thu Jan 1 00:00:00 1970 +++ /sys/src/boot/vt4/include.h Fri Jun 7 00:00:00 2013 @@ -0,0 +1,9 @@ +#include "u.h" +#include "libc.h" +#include "ureg.h" +#include +#include "ppc405.h" +#include "define.h" +#include "data.h" +#include "etherif.h" +#include "prototype.h" diff -Nru /sys/src/boot/vt4/intr.c /sys/src/boot/vt4/intr.c --- /sys/src/boot/vt4/intr.c Thu Jan 1 00:00:00 1970 +++ /sys/src/boot/vt4/intr.c Fri Jun 7 00:00:00 2013 @@ -0,0 +1,101 @@ +/* Xilink XPS interrupt controller */ + +#include "include.h" + +enum { + /* mer bits */ + Merme = 1<<0, /* master enable */ + Merhie = 1<<1, /* hw intr enable */ + + Maxintrs = 8, /* from 32; size reduction */ +}; + +typedef struct { + ulong isr; /* status */ + ulong ipr; /* pending (ro) */ + ulong ier; /* enable */ + ulong iar; /* acknowledge (wo) */ + ulong sieb; /* set ie bits; avoid */ + ulong cieb; /* clear ie bits; avoid */ + ulong ivr; /* vector; silly */ + ulong mer; /* master enable */ +} Intregs; + +typedef struct { + ulong bit; + int (*func)(ulong); +} Intr; + +Intregs *irp = (Intregs *)Intctlr; +Intr intrs[Maxintrs]; +Intr *nextintr; + +static uvlong extintrs; + +/* called from trap to poll for external interrupts */ +void +intr(Ureg *) +{ + int handled; + Intr *ip; + + extintrs++; + dcflush(PTR2UINT(&extintrs), sizeof extintrs); /* seems needed */ + handled = 0; + for (ip = intrs; ip->bit != 0; ip++) + handled |= ip->func(ip->bit); + if (!handled) + print("interrupt with no handler\n"); +} + +void +intrinit(void) +{ + intrack(~0); /* clear dregs */ + putesr(0); /* clears machine check */ + coherence(); + + irp->mer = Merme | Merhie; + irp->ier = 0; /* clear any pending spurious intrs */ + coherence(); + nextintr = intrs; /* touches sram, not dram */ + nextintr->bit = 0; + coherence(); + + intrack(~0); /* clear dregs */ + putesr(0); /* clears machine check */ + coherence(); +} + +/* register func as the interrupt-service routine for bit */ +void +intrenable(ulong bit, int (*func)(ulong)) +{ + Intr *ip; + + if (func == nil) + return; + assert(nextintr < intrs + nelem(intrs)); + assert(bit); + for (ip = intrs; ip->bit != 0; ip++) + if (bit == ip->bit) { + iprint("handler for intr bit %#lux already " + "registered\n", bit); + return; + } + nextintr->bit = bit; + nextintr->func = func; + nextintr++; + coherence(); + irp->ier |= bit; + coherence(); +} + +void +intrack(ulong bit) +{ + if (bit) { + irp->iar = bit; + coherence(); + } +} diff -Nru /sys/src/boot/vt4/ip.h /sys/src/boot/vt4/ip.h --- /sys/src/boot/vt4/ip.h Thu Jan 1 00:00:00 1970 +++ /sys/src/boot/vt4/ip.h Fri Jun 7 00:00:00 2013 @@ -0,0 +1,100 @@ +typedef struct Udphdr Udphdr; +struct Udphdr +{ + uchar d[6]; /* Ethernet destination */ + uchar s[6]; /* Ethernet source */ + uchar type[2]; /* Ethernet packet type */ + + uchar vihl; /* Version and header length */ + uchar tos; /* Type of service */ + uchar length[2]; /* packet length */ + uchar id[2]; /* Identification */ + uchar frag[2]; /* Fragment information */ + + /* Udp pseudo ip really starts here */ + uchar ttl; + uchar udpproto; /* Protocol */ + uchar udpplen[2]; /* Header plus data length */ + uchar udpsrc[4]; /* Ip source */ + uchar udpdst[4]; /* Ip destination */ + uchar udpsport[2]; /* Source port */ + uchar udpdport[2]; /* Destination port */ + uchar udplen[2]; /* data length */ + uchar udpcksum[2]; /* Checksum */ +}; + +typedef struct Etherhdr Etherhdr; +struct Etherhdr +{ + uchar d[6]; + uchar s[6]; + uchar type[2]; + + /* Now we have the ip fields */ + uchar vihl; /* Version and header length */ + uchar tos; /* Type of service */ + uchar length[2]; /* packet length */ + uchar id[2]; /* Identification */ + uchar frag[2]; /* Fragment information */ + uchar ttl; /* Time to live */ + uchar proto; /* Protocol */ + uchar cksum[2]; /* Header checksum */ + uchar src[4]; /* Ip source */ + uchar dst[4]; /* Ip destination */ +}; + +enum +{ + IP_VER = 0x40, + IP_HLEN = 0x05, + UDP_EHSIZE = 22, + UDP_PHDRSIZE = 12, + UDP_HDRSIZE = 20, + ETHER_HDR = 14, + IP_UDPPROTO = 17, + ET_IP = 0x800, + Bcastip = 0xffffffff, + BPportsrc = 68, + BPportdst = 67, + TFTPport = 69, + Timeout = 2000, /* milliseconds; was 5000 */ + Bootrequest = 1, + Bootreply = 2, + Tftp_READ = 1, + Tftp_WRITE = 2, + Tftp_DATA = 3, + Tftp_ACK = 4, + Tftp_ERROR = 5, + Segsize = 512, + TFTPSZ = Segsize+10, +}; + +typedef struct Bootp Bootp; +struct Bootp +{ + uchar op; /* opcode */ + uchar htype; /* hardware type */ + uchar hlen; /* hardware address len */ + uchar hops; /* hops */ + uchar xid[4]; /* a random number */ + uchar secs[2]; /* elapsed since client started booting */ + uchar pad[2]; + uchar ciaddr[4]; /* client IP address (client tells server) */ + uchar yiaddr[4]; /* client IP address (server tells client) */ + uchar siaddr[4]; /* server IP address */ + uchar giaddr[4]; /* gateway IP address */ + uchar chaddr[16]; /* client hardware address */ + char sname[64]; /* server host name (optional) */ + char file[128]; /* boot file name */ + char vend[128]; /* vendor-specific goo */ +}; + +typedef struct Netaddr Netaddr; +struct Netaddr +{ + ulong ip; + ushort port; + char ea[Eaddrlen]; +}; + +extern int eipfmt(Fmt*); diff -Nru /sys/src/boot/vt4/l.s /sys/src/boot/vt4/l.s --- /sys/src/boot/vt4/l.s Thu Jan 1 00:00:00 1970 +++ /sys/src/boot/vt4/l.s Fri Jun 7 00:00:00 2013 @@ -0,0 +1,684 @@ +/* virtex4 ppc405 machine assist */ +#include "ppc405.h" +#include "define.h" + +/* 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 TLBRELO(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)|(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) +#define WRTMSR_EE(s) WORD $((31<<26)|((s)<<21)|(131<<1)) +#define WRTMSR_EEI(e) WORD $((31<<26)|((e)<<15)|(163<<1)) + +/* on some models mtmsr doesn't synchronise enough (eg, 603e) */ +#define MSRSYNC SYNC; ISYNC +#define MSYNC MSRSYNC + +/* + * on the 400 series, the prefetcher madly fetches across RFI, sys call, + * and others; use BR 0(PC) to stop it. + */ +#define RFI WORD $((19<<26)|(50<<1)); BR 0(PC) +#define RFCI WORD $((19<<26)|(51<<1)); BR 0(PC) + +#define MFCCR0(r) WORD $((31<<26) | ((r)<<21) | (0x1d<<11) | (0x13<<16) | (339<<1)) +#define MTCCR0(r) WORD $((31<<26) | ((r)<<21) | (0x1d<<11) | (0x13<<16) | (467<<1)) + +/* 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 + + NOSCHED + +TEXT start<>(SB), 1, $-4 + /* virtex4 CR 203746 patch for ppc405 errata cpu_213 */ + MFCCR0(3) + OR $0x50000000, R3 + MTCCR0(3) + + XORCC R0, R0 /* from now on R0 == 0 */ + MOVW R0, CR + + MOVW R0, SPR(SPR_ESR) + /* + * setup MSR + * turn off interrupts & mmu + * use 0x000 as exception prefix + * enable machine check + */ + MOVW $(MSR_ME), R1 + ISYNC + MOVW R1, MSR + MSYNC + ISYNC + + /* setup SB for pre mmu */ + MOVW $setSB(SB), R2 /* SB until mmu on */ + +PROG('\r') +PROG('\n') + + /* + * Invalidate the caches. + */ +// ICCCI(0, 0) + MOVW R0, SPR(SPR_ICCR) + ICCCI(0, 2) /* errata cpu_121 reveals that EA is used; we'll use SB */ + ISYNC + DCCCI(0, 0) + MSYNC + + MOVW $((DCACHEWAYSIZE/DCACHELINESZ)-1), R3 + MOVW R3, CTR + MOVW R0, R3 +dcinv: + DCCCI(0,3) + ADD $32, R3 + BDNZ dcinv + + /* + * cache is write-through; no user-defined 0; big endian throughout. + * start with caches off until we have zeroed all of memory once. + */ + MOVW $~0, R3 + MOVW R3, SPR(SPR_DCWR) /* write-through everywhere*/ + /* starting from the high bit, each bit represents 128MB */ + MOVW R0, R3 /* region bits */ + MOVW R3, SPR(SPR_DCCR) + MOVW R3, SPR(SPR_ICCR) + ISYNC + MOVW R0, SPR(SPR_SU0R) + MOVW R0, SPR(SPR_SLER) + ISYNC + + NOR R3, R3 /* no speculative access in uncached mem */ + MOVW R3, SPR(SPR_SGR) + ISYNC + + /* + * set other system configuration values + */ + MOVW R0, SPR(SPR_PIT) + MOVW $~0, R3 + MOVW R3, SPR(SPR_TSR) + + + /* run the boot loader with the mmu off */ + + /* + * invalidate the caches again to flush any addresses + * below KZERO + */ + ICCCI(0, 0) + ISYNC + + /* + * Set up SB, vector space (16KiB, 64KiB aligned), + * extern registers (m->, up->) and stack. + * Mach (and stack) will be cleared along with the + * rest of BSS below if this is CPU#0. + * Memstart is the first free memory location + * after the kernel. + */ + MOVW $setSB(SB), R2 /* (SB) */ + +PROG('P') +PROG('l') + + MOVW $PHYSSRAM, R6 /* vectors at bottom of sram */ + MOVW R6, SPR(SPR_EVPR) + + /* only one cpu, # zero */ + /* sizeof(Mach) is currently 19*4 = 76 bytes */ + MOVW R6, R(MACH) /* m-> before 1st vector */ + + MOVW R0, R(USER) /* up-> */ + MOVW $0xfffffffc, R1 /* put stack in sram temporarily */ + +_CPU0: /* boot processor */ + MOVW $edata-4(SB), R3 + MOVW R0, R4 + SUB $8, R4 /* sram end, below JMP */ +_clrbss: /* clear BSS */ + MOVWU R0, 4(R3) + CMP R3, R4 + BNE _clrbss + + MOVW R0, memstart(SB) /* start of unused memory: dram */ + MOVW R6, vectorbase(SB) /* 64KiB aligned vector base, for trapinit */ + +PROG('a') +PROG('n') +PROG(' ') + BL main(SB) + BR 0(PC) + RETURN + +TEXT cacheson(SB), 1, $-4 + /* cache is write-through; no user-defined 0; big endian throughout */ + MOVW $~0, R3 + MOVW R3, SPR(SPR_DCWR) /* write-through everywhere*/ + /* + * cache bottom 128MB (dram) & top 128MB (sram), but not I/O reg.s. + * starting from the high bit, each bit represents another 128MB. + */ + MOVW $(1<<31 | 1<<0), R3 + MOVW R3, SPR(SPR_DCCR) + MOVW R3, SPR(SPR_ICCR) + ISYNC + MOVW R0, SPR(SPR_SU0R) + MOVW R0, SPR(SPR_SLER) + ISYNC + + MOVW R3, R4 + NOR R3, R3 /* no speculative access in uncached mem */ + MOVW R3, SPR(SPR_SGR) + ISYNC + MOVW R4, R3 /* return value: true iff caches on */ + RETURN + +TEXT splhi(SB), 1, $-4 + MOVW MSR, R3 + WRTMSR_EEI(0) +// MOVW LR, R31 +// MOVW R31, 4(R(MACH)) /* save PC in m->splpc */ + 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 + WRTMSR_EE(3) + RETURN + +TEXT spllo(SB), 1, $-4 + MOVW MSR, R3 + WRTMSR_EEI(1) + RETURN + +TEXT spldone(SB), 1, $-4 + RETURN + +TEXT islo(SB), 1, $-4 + MOVW MSR, R3 + RLWNM $0, R3, $MSR_EE, R3 + RETURN + +TEXT dcbi(SB), 1, $-4 /* dcbi(addr) */ + DCBI (R3) + RETURN + +TEXT icflush(SB), 1, $-4 /* icflush(virtaddr, count) */ + 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 + +TEXT sync(SB), 1, $-4 /* sync() */ + SYNC + RETURN + +TEXT dcflush(SB), 1, $-4 /* dcflush(virtaddr, count) */ + 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: + SYNC + RETURN + +/* copied from ../vt5/l.s; hope it's right */ +TEXT cachesinvalidate(SB), 1, $-4 + ICCCI(0, 2) /* errata cpu_121 reveals that EA is used; we'll use SB */ + DCCCI(0, 2) /* dcache must not be in use (or just needs to be clean?) */ + MSYNC + RETURN + +TEXT getpit(SB), 1, $0 + MOVW SPR(SPR_PIT), R3 + RETURN + +TEXT putpit(SB), 1, $0 + MOVW R3, SPR(SPR_PIT) + RETURN + +TEXT putpid(SB), 1, $0 + MOVW R3, SPR(SPR_PID) + RETURN + +TEXT getpid(SB), 1, $0 + MOVW SPR(SPR_PID), R3 + RETURN + +/* 405s have no PIR, so use low bits of PVR, which rae can set. */ +TEXT getpir(SB), 1, $-4 + MOVW SPR(SPR_PVR), R3 + ANDCC $017, R3 + RETURN + +TEXT gettbl(SB), 1, $0 + MFTB(TBRL, 3) + RETURN + +TEXT gettbu(SB), 1, $0 + MFTB(TBRU, 3) + RETURN + +TEXT gettsr(SB), 1, $0 + MOVW SPR(SPR_TSR), R3 + RETURN + +TEXT puttsr(SB), 1, $0 + MOVW R3, SPR(SPR_TSR) + RETURN + +TEXT gettcr(SB), 1, $0 + MOVW SPR(SPR_TCR), R3 + RETURN + +TEXT puttcr(SB), 1, $0 + MOVW R3, SPR(SPR_TCR) + RETURN + +TEXT getpvr(SB), 1, $0 + MOVW SPR(SPR_PVR), R3 + RETURN + +TEXT getmsr(SB), 1, $0 + MOVW MSR, R3 + RETURN + +TEXT putmsr(SB), 1, $0 + SYNC + MOVW R3, MSR + MSRSYNC + RETURN + +TEXT getesr(SB), 1, $0 + MOVW SPR(SPR_ESR), R3 + RETURN + +TEXT putesr(SB), 1, $0 + MOVW R3, SPR(SPR_ESR) + RETURN + +TEXT putevpr(SB), 1, $0 + MOVW R3, SPR(SPR_EVPR) + RETURN + +TEXT setsp(SB), 1, $0 + MOVW R3, R1 + RETURN + +TEXT getdear(SB), 1, $0 + MOVW SPR(SPR_DEAR), R3 + RETURN + +TEXT tas32(SB), 1, $0 + SYNC + MOVW R3, R4 + MOVW $0xdead,R5 +tas1: + MSYNC + LWAR (R4), R3 + CMP R3, $0 + BNE tas0 + DCBT (R4) /* fix 405 errata cpu_210 */ + STWCCC R5, (R4) + BNE tas1 +tas0: + SYNC + ISYNC + RETURN + +TEXT eieio(SB), 1, $0 + EIEIO + RETURN + +TEXT syncall(SB), 1, $0 + SYNC + ISYNC + RETURN + +TEXT _xinc(SB), 1, $0 /* void _xinc(long *); */ + MOVW R3, R4 +xincloop: + LWAR (R4), R3 + ADD $1, R3 + DCBT (R4) /* fix 405 errata cpu_210 */ + STWCCC R3, (R4) + BNE xincloop + RETURN + +TEXT _xdec(SB), 1, $0 /* long _xdec(long *); */ + MOVW R3, R4 +xdecloop: + LWAR (R4), R3 + ADD $-1, R3 + DCBT (R4) /* fix 405 errata cpu_210 */ + STWCCC R3, (R4) + BNE xdecloop + RETURN + + +#define SPR_CSRR0 0x03a /* Critical Save/Restore Register 0 */ +#define SPR_CSRR1 0x03b /* Critical Save/Restore Register 1 */ +//#define SPR_DEAR 0x03d /* Data Error Address Register */ + +#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_MCSRR0 0x23a +#define SPR_MCSRR1 0x23b + +#define SAVER0 SPR_SPRG0 /* shorthand use in save/restore */ +#define SAVER1 SPR_SPRG1 +#define SAVELR SPR_SPRG2 +#define SAVEXX SPR_SPRG3 + +#define UREGSPACE (UREGSIZE+8) + +#define RTBL 28 /* time stamp tracing */ + +/* + * the 405 does not follow Book E: traps turn the mmu off. + * 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 */ + 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 sysrforkret */ + MFTB(TBRL, RTBL) + BL saveureg(SB) + +// MOVW $mach0(SB), R(MACH) /* FIX FIX FIX */ +// MOVW 8(R(MACH)), R(USER) /* FIX FIX FIX */ +//try this: +/* 405s have no PIR; could use PVR */ +// MOVW SPR(SPR_PIR), R4 /* PIN */ +// SLW $2, R4 /* offset into pointer array */ + MOVW $0, R4 /* assume cpu 0 */ + MOVW $machptr(SB), R(MACH) /* pointer array */ + ADD R4, R(MACH) /* pointer to array element */ + MOVW (R(MACH)), R(MACH) /* m-> */ + MOVW 8(R(MACH)), R(USER) /* up-> */ + + 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 */ + SYNC /* fix 405 errata cpu_210 */ + 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 sysrforkret */ + BL saveureg(SB) + +// MOVW $mach0(SB), R(MACH) /* FIX FIX FIX */ +// MOVW 8(R(MACH)), R(USER) +//try this: +/* 405s have no PIR */ +// MOVW SPR(SPR_PIR), R4 /* PIN */ +// SLW $2, R4 /* offset into pointer array */ + MOVW $0, R4 /* assume cpu 0 */ + MOVW $machptr(SB), R(MACH) /* pointer array */ + ADD R4, R(MACH) /* pointer to array element */ + MOVW (R(MACH)), R(MACH) /* m-> */ + MOVW 8(R(MACH)), R(USER) /* up-> */ + + 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 sysrforkret */ + BL saveureg(SB) + +// MOVW $mach0(SB), R(MACH) /* FIX FIX FIX */ +// MOVW 8(R(MACH)), R(USER) +//try this: +/* 405s have no PIR */ +// MOVW SPR(SPR_PIR), R4 /* PIN */ +// SLW $2, R4 /* offset into pointer array */ + MOVW $0, R4 /* assume cpu 0 */ + MOVW $machptr(SB), R(MACH) /* pointer array */ + ADD R4, R(MACH) /* pointer to array element */ + MOVW (R(MACH)), R(MACH) /* m-> */ + MOVW 8(R(MACH)), R(USER) /* up-> */ + + 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* */ + DCBT (R1) /* fix 405 errata cpu_210 */ + STWCCC R3, (R1) /* break any pending reservations */ + MOVW $0, R0 /* compiler/linker expect R0 to be zero */ + RETURN diff -Nru /sys/src/boot/vt4/libc.h /sys/src/boot/vt4/libc.h --- /sys/src/boot/vt4/libc.h Thu Jan 1 00:00:00 1970 +++ /sys/src/boot/vt4/libc.h Fri Jun 7 00:00:00 2013 @@ -0,0 +1,102 @@ +/* + * functions (possibly) linked in, complete, from libc. + */ +#define nelem(x) (sizeof(x)/sizeof((x)[0])) +#define offsetof(s, m) (ulong)(&(((s*)0)->m)) +#define assert(x) if(x){}else _assert("x") + +/* + * mem routines + */ +extern void* memset(void*, int, ulong); +extern int memcmp(void*, void*, ulong); +extern void* memmove(void*, void*, ulong); + +/* + * string routines + */ +extern int cistrcmp(char *, char *); +extern int cistrncmp(char *, char *, int); +extern char *strchr(char *, int); +extern int strcmp(char *, char *); +extern char* strecpy(char*, char*, char*); +extern long strlen(char*); +extern int strncmp(char *, char *, int); +extern char* strncpy(char*, char*, long); +extern char* strstr(char *, char *); +extern int tokenize(char*, char**, int); + +/* + * malloc + */ +extern void free(void*); +extern void* malloc(ulong); +extern void* mallocalign(ulong, ulong, long, ulong); +extern int mallocinit(void*, ulong); + +/* + * print routines + */ +typedef struct Fmt Fmt; +struct Fmt { + uchar runes; /* output buffer is runes or chars? */ + void* start; /* of buffer */ + void* to; /* current place in the buffer */ + void* stop; /* end of the buffer; overwritten if flush fails */ + int (*flush)(Fmt*); /* called when to == stop */ + void* farg; /* to make flush a closure */ + int nfmt; /* num chars formatted so far */ + va_list args; /* args passed to dofmt */ + int r; /* % format Rune */ + int width; + int prec; + ulong flags; +}; + +extern int print(char*, ...); +extern char* seprint(char*, char*, char*, ...); +extern char* vseprint(char*, char*, char*, va_list); + +#pragma varargck argpos print 1 +#pragma varargck argpos seprint 3 + +#pragma varargck type "lld" vlong +#pragma varargck type "llx" vlong +#pragma varargck type "lld" uvlong +#pragma varargck type "llx" uvlong +#pragma varargck type "ld" long +#pragma varargck type "lx" long +#pragma varargck type "ld" ulong +#pragma varargck type "lx" ulong +#pragma varargck type "d" int +#pragma varargck type "x" int +#pragma varargck type "c" int +#pragma varargck type "C" int +#pragma varargck type "d" uint +#pragma varargck type "x" uint +#pragma varargck type "c" uint +#pragma varargck type "C" uint +#pragma varargck type "s" char* +#pragma varargck type "q" char* +#pragma varargck type "S" Rune* +#pragma varargck type "%" void +#pragma varargck type "p" uintptr +#pragma varargck type "p" void* +#pragma varargck flag ',' +#pragma varargck type "E" uchar* /* eipfmt */ +#pragma varargck type "V" uchar* /* eipfmt */ + +extern int fmtinstall(int, int (*)(Fmt*)); +extern int dofmt(Fmt*, char*); + +/* + * one-of-a-kind + */ +extern void _assert(char*); +extern uintptr getcallerpc(void*); +extern long strtol(char*, char**, int); +extern ulong strtoul(char*, char**, int); +extern void longjmp(jmp_buf, int); +extern int setjmp(jmp_buf); + +extern char etext[], edata[], end[]; diff -Nru /sys/src/boot/vt4/llfifo.c /sys/src/boot/vt4/llfifo.c --- /sys/src/boot/vt4/llfifo.c Thu Jan 1 00:00:00 1970 +++ /sys/src/boot/vt4/llfifo.c Fri Jun 7 00:00:00 2013 @@ -0,0 +1,211 @@ +/* + * Xilinx Local Link FIFOs for Temac, in pairs (rx and tx). + */ +#include "include.h" + +enum { + Reset = 0xa5, /* magic [tr]dfr & llr value */ + + /* dmacr; copied from dma.c */ + Sinc = 1<<31, /* source increment */ + Dinc = 1<<30, /* dest increment */ + + /* field masks */ + + Bytecnt = (1<<11) - 1, + Wordcnt = (1<<9) - 1, +}; + +enum { /* register's bits */ + /* isr, ier registers (*?e->*ee) */ + Rpure = 1<<31, /* rx packet underrun read error */ + Rpore = 1<<30, /* rx packet overrun read error */ + Rpue = 1<<29, /* rx packet underrun error */ + Tpoe = 1<<28, /* tx packet overrun error */ + Tc = 1<<27, /* tx complete */ + Rc = 1<<26, /* rx complete */ + Tse = 1<<25, /* tx size error */ + Trc = 1<<24, /* tx reset complete */ + Rrc = 1<<23, /* rx reset complete */ +}; + +typedef struct Llfiforegs Llfiforegs; +typedef struct Llfifosw Llfifosw; + +struct Llfiforegs { + ulong isr; /* intr status */ + ulong ier; /* intr enable */ + + ulong tdfr; /* tx data fifo reset */ + ulong tdfv; /* tx data fifo vacancy (words free) */ + ulong tdfd; /* tx data fifo write port */ + ulong tlf; /* tx length fifo */ + + ulong rdfr; /* rx data fifo reset */ + ulong rdfo; /* rx data fifo occupancy */ + ulong rdfd; /* rx data fifo read port */ + ulong rlf; /* tx length fifo */ + + ulong llr; /* locallink reset */ +}; +struct Llfifosw { + Llfiforegs *regs; +}; + +static Llfiforegs *frp = (Llfiforegs *)Llfifo; +static Ether *llether; + +/* + * as of dma controller v2, keyhole operations are on ulongs, + * but otherwise it's as if memmove were used. + * addresses need not be word-aligned, though registers are. + */ +static void +fifocpy(void *vdest, void *vsrc, uint bytes, ulong flags) +{ + int words; + ulong *dest, *dstbuf, *src; + /* +2*BY2WD is slop for alignment */ + static uchar buf[ETHERMAXTU+8+2*BY2WD]; + + dest = vdest; + src = vsrc; + assert(bytes <= sizeof buf); + words = bytes / BY2WD; + if (bytes % BY2WD != 0) + words++; + + switch (flags & (Sinc | Dinc)) { + case Sinc | Dinc: + memmove(vdest, vsrc, bytes); + break; + case Sinc: /* mem to register */ + src = (ulong *)ROUNDUP((uvlong)buf, BY2WD); + memmove(src, vsrc, bytes); /* ensure src alignment */ + assert((uintptr)src % BY2WD == 0); + assert((uintptr)dest % BY2WD == 0); + while (words-- > 0) + *dest = *src++; + break; + case Dinc: /* register to mem */ + dest = dstbuf = (ulong *)ROUNDUP((uvlong)buf, BY2WD); + assert((uintptr)src % BY2WD == 0); + assert((uintptr)dest % BY2WD == 0); + while (words-- > 0) + *dest++ = *src; + memmove(vdest, dstbuf, bytes); /* ensure dest alignment */ + break; + case 0: /* register-to-null or vice versa */ + while (words-- > 0) + *dest = *src; + break; + } +} + +static void +discardinpkt(int len) /* discard the rx fifo's packet */ +{ + ulong null; + + fifocpy(&null, &frp->rdfd, len, 0); + coherence(); +} + +int +llfifointr(ulong bit) +{ + ulong len, sts; + Ether *ether; + RingBuf *rb; + static uchar zaddrs[Eaddrlen * 2]; + + sts = frp->isr; + if (sts == 0) + return 0; /* not for me */ + ether = llether; + /* it's important to drain all packets in the rx fifo */ + while ((frp->rdfo & Wordcnt) != 0) { + assert((frp->rdfo & ~Wordcnt) == 0); + len = frp->rlf & Bytecnt; /* read rlf from fifo */ + assert((len & ~Bytecnt) == 0); + assert(len > 0 && len <= ETHERMAXTU); + rb = ðer->rb[ether->ri]; + if (rb->owner == Interface) { + /* from rx fifo into ring buffer */ + fifocpy(rb->pkt, &frp->rdfd, len, Dinc); + if (memcmp(rb->pkt, zaddrs, sizeof zaddrs) == 0) { + iprint("ether header with all-zero mac " + "addresses\n"); + continue; + } + rb->len = len; + rb->owner = Host; + coherence(); + ether->ri = NEXT(ether->ri, ether->nrb); + coherence(); + } else { + discardinpkt(len); + /* not too informative during booting */ + iprint("llfifo: no buffer for input pkt\n"); + } + } + + if (sts & Tc) + ether->tbusy = 0; + ether->transmit(ether); + + frp->isr = sts; /* extinguish intr source */ + coherence(); + + intrack(bit); + sts &= ~(Tc | Rc); + if (sts) + iprint("llfifo isr %#lux\n", sts); + return 1; +} + +void +llfiforeset(void) +{ + frp->tdfr = Reset; + frp->rdfr = Reset; + coherence(); + while ((frp->isr & (Trc | Rrc)) != (Trc | Rrc)) + ; +} + +void +llfifoinit(Ether *ether) +{ + llether = ether; + frp->ier = 0; + frp->isr = frp->isr; /* extinguish intr source */ + coherence(); + + intrenable(Intllfifo, llfifointr); + coherence(); + frp->ier = Rc | Tc; + coherence(); +} + +void +llfifotransmit(uchar *ubuf, unsigned len) +{ + int wds; + + llether->tbusy = 1; + + assert(len <= ETHERMAXTU); + wds = ROUNDUP(len, BY2WD) / BY2WD; + + /* wait for tx fifo to drain */ + while ((frp->tdfv & Wordcnt) < wds) + ; + + /* to tx fifo */ + assert((frp->tdfv & ~Wordcnt) == 0); + fifocpy(&frp->tdfd, ubuf, len, Sinc); + coherence(); + frp->tlf = len; /* send packet in tx fifo to ether */ + coherence(); +} diff -Nru /sys/src/boot/vt4/load.c /sys/src/boot/vt4/load.c --- /sys/src/boot/vt4/load.c Thu Jan 1 00:00:00 1970 +++ /sys/src/boot/vt4/load.c Fri Jun 7 00:00:00 2013 @@ -0,0 +1,840 @@ +#include "include.h" +#include "fs.h" + +enum { + Dontprint, + Print, + + Datamagic = 0xfacebabe, +}; + +int securemem; + +static char *etherparts[] = { "*", 0 }; +static char *etherinis[] = { + "/cfg/pxe/%E", + 0 +}; + +Type types[] = { + { Tether, + Fini|Fbootp, + etherinit, etherinitdev, + pxegetfspart, 0, bootpboot, + etherprintdevs, + etherparts, + etherinis, + }, +}; + +static char *typenm[] = { + [Tether] "ether", +}; + +typedef struct Mode Mode; + +enum { + Dany = -1, + Nmedia = 2, /* size reduction; was 16 */ +}; + +enum { /* mode */ + Mauto, + Mlocal, + Manual, + NMode, +}; + +typedef struct Medium Medium; +struct Medium { + Type* type; + ushort flag; + ushort dev; + char name[NAMELEN]; + + Fs *inifs; + char *part; + char *ini; + + Medium* next; +}; + +typedef struct Mode { + char* name; + ushort mode; +} Mode; + +extern char bdata[], edata[], end[], etext[]; + +static Medium media[Nmedia]; +static Medium *curmedium = media; + +static Mode modes[NMode+1] = { + [Mauto] { "auto", Mauto, }, + [Mlocal] { "local", Mlocal, }, + [Manual] { "manual", Manual, }, +}; + +Mach* machptr[MAXMACH]; + +ulong cpuentry = 0; + +char **ini; +char *defaultpartition; +char *persist; + +int debugload; +int iniread; +int pxe = 1; +int scsi0port; +int vga; + +uintptr memstart; /* set before main called */ +uintptr vectorbase; /* set before main called */ + +static uintptr memsz; + +static Medium* +parse(char *line, char **file) +{ + char *p; + Type *tp; + Medium *mp; + + if(p = strchr(line, '!')) { + *p++ = 0; + *file = p; + } else + *file = ""; + + tp = types; + for(mp = tp->media; mp; mp = mp->next) + if(strcmp(mp->name, line) == 0) + return mp; + if(p) + *--p = '!'; + return nil; +} + +static int +boot(Medium *mp, char *file) +{ + Type *tp; + Medium *xmp; + static int didaddconf; + Boot b; + + memset(&b, 0, sizeof b); + b.state = INITKERNEL; + + if(didaddconf == 0) { + didaddconf = 1; + tp = types; + if(tp->addconf) + for(xmp = tp->media; xmp; xmp = xmp->next) + (*tp->addconf)(xmp->dev); + } + + seprint(BOOTLINE, BOOTLINE + BOOTLINELEN, "%s!%s", mp->name, file); + print("booting %s!%s\n", mp->name, file); + return (*mp->type->boot)(mp->dev, file, &b); +} + +static Medium* +allocm(Type *tp) +{ + Medium **l; + + if(curmedium >= &media[Nmedia]) + return 0; + + for(l = &tp->media; *l; l = &(*l)->next) + ; + *l = curmedium++; + return *l; +} + +Medium* +probe(int type, int flag, int dev) +{ + Type *tp; + int i; + Medium *mp; + File f; + Fs *fs; + char **partp; + + tp = types; + if(type != Tany && type != tp->type) + return 0; + + if(flag != Fnone) + for(mp = tp->media; mp; mp = mp->next) + if((flag & mp->flag) && (dev == Dany || dev == mp->dev)) + return mp; + if((tp->flag & Fprobe) == 0){ + tp->flag |= Fprobe; + tp->mask = (*tp->init)(); + } + + for(i = 0; tp->mask; i++){ + if((tp->mask & (1<mask &= ~(1<dev = i; + mp->flag = tp->flag; + mp->type = tp; + (*tp->initdev)(i, mp->name); + + if(mp->flag & Fini){ + mp->flag &= ~Fini; + for(partp = tp->parts; *partp; partp++){ + if((fs = (*tp->getfspart)(i, *partp, 0)) == nil) + continue; + + for(ini = tp->inis; *ini; ini++) + if(fswalk(fs, *ini, &f) > 0){ + mp->inifs = fs; + mp->part = *partp; + mp->ini = f.path; + mp->flag |= Fini; + goto Break2; + } + } + } + Break2: + if((flag & mp->flag) && (dev == Dany || dev == i)) + return mp; + } + return 0; +} + +enum { + Kilo = 1024, +}; + +/* make sure we don't get the write system call from libc */ +long +write(int fd, void *buf, long nbytes) +{ + USED(fd); + vuartputs(buf, nbytes); + return nbytes; +} + +/* + * write zero words to an entire cache line (the one containing addr). + * does not flush the data cache. + */ +void +cacheline0(uintptr addr) +{ + ulong *sp, *endmem; + + addr &= ~(DCACHELINESZ - 1); + endmem = (ulong *)(addr + DCACHELINESZ); + for (sp = (ulong *)addr; sp < endmem; sp++) + *sp = 0; +// coherence(); +} + +/* force the four qtm write buffers to be retired to dram by filling them. */ +void +flushwrbufs(void) +{ + if (!securemem) + return; + cacheline0(PHYSDRAM); + cacheline0(PHYSDRAM + DCACHELINESZ); + cacheline0(PHYSDRAM + 2*DCACHELINESZ); + cacheline0(PHYSDRAM + 3*DCACHELINESZ); + coherence(); +} + +static void +vfyzeros(ulong *addr, ulong *end) +{ + ulong wd; + ulong *sp; + + for (sp = addr; sp < end; sp++) { + wd = *sp; + if (wd != 0) { + PROG('?') + panic("bad dram: %#p read back as %#lux not 0", sp, wd); + } + } +} + +static int +memreset(void) +{ + int i, cnt; + uintptr addr, endmem; + + cnt = 0; + if (securemem) + cnt = qtmmemreset(); + else + /* normal dram init. should take 100—250 ms. */ + for (i = 10*1000*1000; i-- > 0; ) + cnt++; +PROG('t') + /* + * dram must be done initialising now, + * but qtm needs us to zero it *all* before any other use, + * to set the macs. even for non-qtm dram, it might be wise + * to ensure that all the ecc bits are set. + */ + memsz = memsize(); /* may carefully probe qtm dram */ + qtmerrtest("sizing memory"); + + dcflush(PHYSSRAM, (1ULL << 32) - PHYSSRAM); + cachesinvalidate(); + + endmem = PHYSDRAM + memsz; + for (addr = PHYSDRAM; addr < endmem; addr += DCACHELINESZ) { + cacheline0(addr); + qtmerrtestaddr(addr); + } + assert(addr == endmem); + coherence(); + flushwrbufs(); + qtmerrtest("zeroing dram"); + +#ifdef PARANOID + vfyzeros((ulong *)PHYSDRAM, (ulong *)endmem); +#else + vfyzeros((ulong *)(endmem - MB), (ulong *)endmem); +#endif + dcflush(PHYSDRAM, memsz); + dcflush(PHYSSRAM, (1ULL << 32) - PHYSSRAM); + cachesinvalidate(); + + /* + * Hallelujah! We can finally treat qtm dram just like real memory, + * except that the last (partial) page is funny and should be avoided + * after initialising it. + * It happens even with caches off, so it's a bit hard to explain + * why it should be funny. + */ + memsz &= ~(BY2PG - 1); + endmem = PHYSDRAM + memsz; + +#ifdef PARANOID + vfyzeros((ulong *)PHYSDRAM, (ulong *)endmem); +#else + vfyzeros((ulong *)PHYSDRAM, (ulong *)(PHYSDRAM + MB)); + vfyzeros((ulong *)(endmem - MB), (ulong *)endmem); +#endif + qtmerrtest("reading back dram"); + return cnt; +} + +static void +memtest(void) +{ + ulong wd; + ulong *sp, *endmem; + + /* + * verify that (possibly secure) dram is more or less working. + * write address of each word into that word. + */ +#ifdef PARANOID + endmem = (ulong *)(PHYSDRAM + memsz); +#else + endmem = (ulong *)(PHYSDRAM + MB); /* just the first MB */ +#endif + for (sp = (ulong *)PHYSDRAM; sp < endmem; sp++) + *sp = (ulong)sp; + coherence(); + /* no need to flush caches, caches are off */ + + /* + * now verify that each word contains its address. + */ + for (sp = (ulong *)PHYSDRAM; sp < endmem; sp++) { + wd = *sp; + if (wd != (ulong)sp) { + PROG('?') + panic("bad dram: %#p read back as %#lux", sp, wd); + } + } +PROG('t') +/* memset((void *)PHYSDRAM, 0, memsz); /* good hygiene? */ +} + +enum { + Testbase = PHYSDRAM + 0x4000, +}; + +void +meminit(void) +{ + int i; + uchar *memc; + ulong *mem; + +// iprint("sanity: writing..."); + mem = (ulong *)Testbase; + memc = (uchar *)Testbase; + + memset(mem, 0252, Kilo); + coherence(); + dcflush(Testbase, Kilo); + +// iprint("reading..."); + for (i = 0; i < Kilo; i++) + if (memc[i] != 0252) + panic("dram not retaining data"); + +// iprint("zeroing..."); + memset(mem, '\0', Kilo); + coherence(); + dcflush(Testbase, Kilo); + if (*mem) + panic("zeroed dram not zero"); +// iprint("\n"); +} + +static int idx; +static char numb[32]; + +static void +gendigs(ulong n) +{ + int dig; + + do { + dig = n % 16; + if (dig > 9) + numb[idx--] = 'A' + dig - 10; + else + numb[idx--] = '0' + dig; + } while ((n /= 16) > 0); +} + +static void +prnum(ulong n) +{ +// PROG(' ') + idx = nelem(numb) - 1; + gendigs(n); + for (; idx < nelem(numb); idx++) + PROG(numb[idx]) + PROG('\n') + PROG('\r') +} + +extern uintptr vectorbase; + +void +main(void) +{ + int flag, i, j, mode, tried; + char def[2*NAMELEN], line[80], *p, *file; + Medium *mp; + Type *tp; + static int savcnt, caching; + static ulong vfy = Datamagic; + + /* + * all cpus start executing at reset address, thus start of sram. + * cpu0 loads the kernel; + * all others just jump to the (by now) loaded kernel. + */ + /* "\r\nPlan " already printed by l.s */ + if (getpir() != 0) { + for (j = 0; j < 6; j++) + for (i = 2*1000*1000*1000; i > 0; i--) + ; + + cachesinvalidate(); + while(cpuentry == 0) + cachesinvalidate(); + + for (j = 0; j < 6; j++) + for (i = 2*1000*1000*1000; i > 0; i--) + ; + warp9(PADDR(cpuentry)); + } + + /* + * we may have to realign the data segment; apparently ql -R4096 + * does not pad the text segment. + */ + if (vfy != Datamagic) + memmove(bdata, etext, edata - bdata); + if (vfy != Datamagic) { + PROG('?') + panic("misaligned data segment"); + } +// memset(edata, 0, end - edata); /* zero bss */ + +PROG('9') + /* + * trap vectors are in sram, so we don't have to wait for dram + * to become ready to initialise them. + */ + trapinit(); +PROG(' ') + securemem = (probeaddr(Qtm) >= 0); + if (securemem) + PROG('q') + else + PROG('n') +PROG(' ') + + /* + * the stack is now at top of sram, and entry to main just pushed + * stuff onto it. the new stack will be at the top of dram, + * when dram finishes initialising itself. + */ +PROG('B') +PROG('o') +PROG('o') + /* do voodoo to make dram usable; prints "t". sets memsz. */ + savcnt = memreset(); +PROG('s') + memtest(); /* also prints "t" */ + intrinit(); + + caching = cacheson(); + + /* + * switch to the dram stack just below the end of dram. + * have to allow enough room for main's local variables, + * to avoid address faults. + */ + +PROG('r') + setsp(memsz - BY2PG); + +PROG('a') + meminit(); + /* memory is now more or less normal from a software perspective. */ + + memset(m, 0, sizeof(Mach)); + m->machno = 0; + m->up = nil; + MACHP(0) = m; + + /* + * the Mach struct is now initialised, so we can print safely. + */ + +// print("\nPlan 9 bootstrap"); /* already printed, 1 char at a time */ + print("p"); +// print("\n%d iterations waiting for %s init done\n", +// savcnt, (securemem? "qtm": "dram")); + if (securemem) + print("; secure memory"); + print("; caches %s\n", (caching? "on": "off")); + print("\n"); + if ((uintptr)end < PHYSSRAM) + panic("too big; end %#p before sram @ %#ux", end, PHYSSRAM); + print("memory found: %,lud (%lux)\n", memsz, memsz); + + spllo(); + clockinit(); + prcpuid(); +// etherinit(); /* probe() calls this */ + kbdinit(); + + /* + * find and read plan9.ini, setting configuration variables. + */ + tp = types; +// debug = debugload = 1; // DEBUG + if(pxe && (mp = probe(tp->type, Fini, Dany)) && mp->flag & Fini){ + if (debug) + print("using %s!%s!%s\n", mp->name, mp->part, mp->ini); +// iniread = !dotini(mp->inifs); + } + + /* + * we should now have read plan9.ini, if any. + */ + persist = getconf("*bootppersist"); + + tried = 0; + mode = Mauto; + + p = getconf("bootfile"); + if(p != 0) { + mode = Manual; + for(i = 0; i < NMode; i++){ + if(strcmp(p, modes[i].name) == 0){ + mode = modes[i].mode; + goto done; + } + } + if((mp = parse(p, &file)) == nil) + print("Unknown boot device: %s\n", p); + else + tried = boot(mp, file); + } +done: + if(tried == 0 && mode != Manual){ + flag = Fany; + if(mode == Mlocal) + flag &= ~Fbootp; + if((mp = probe(Tany, flag, Dany))) + boot(mp, ""); + if (debugload) + print("end auto probe\n"); + } + + def[0] = 0; + if(p = getconf("bootdef")) + strecpy(def, def + sizeof def, p); + flag = 0; + tp = types; + for(mp = tp->media; mp; mp = mp->next){ + if(flag == 0){ + flag = 1; + print("Boot devices:"); + } + (*tp->printdevs)(mp->dev); + } + if(flag) + print("\n"); + + /* + * e.g., *bootppersist=ether0 + * + * previously, we looped in bootpopen if we were pxeload or if + * *bootppersist was set. that doesn't work well for pxeload where + * bootp will never succeed on the first interface but only on another + * interface. + */ +//print("boot mode %s\n", modes[mode].name); + if (mode == Mauto && persist != nil && + (mp = parse(persist, &file)) != nil) { + boot(mp, file); + print("pausing before retry..."); + delay(30*1000); + print("\n"); + } + + for(;;){ + if(getstr("boot from", line, sizeof(line), def, + (mode != Manual)*15) >= 0) + if(mp = parse(line, &file)) + boot(mp, file); + def[0] = 0; + } +} + +int +getfields(char *lp, char **fields, int n, char sep) +{ + int i; + + for(i = 0; lp && *lp && i < n; i++){ + while(*lp == sep) + *lp++ = 0; + if(*lp == 0) + break; + fields[i] = lp; + while(*lp && *lp != sep){ + if(*lp == '\\' && *(lp+1) == '\n') + *lp++ = ' '; + lp++; + } + } + return i; +} + +int +cistrcmp(char *a, char *b) +{ + int ac, bc; + + for(;;){ + ac = *a++; + bc = *b++; + + if(ac >= 'A' && ac <= 'Z') + ac = 'a' + (ac - 'A'); + if(bc >= 'A' && bc <= 'Z') + bc = 'a' + (bc - 'A'); + ac -= bc; + if(ac) + return ac; + if(bc == 0) + break; + } + return 0; +} + +int +cistrncmp(char *a, char *b, int n) +{ + unsigned ac, bc; + + while(n > 0){ + ac = *a++; + bc = *b++; + n--; + + if(ac >= 'A' && ac <= 'Z') + ac = 'a' + (ac - 'A'); + if(bc >= 'A' && bc <= 'Z') + bc = 'a' + (bc - 'A'); + + ac -= bc; + if(ac) + return ac; + if(bc == 0) + break; + } + + return 0; +} + +#define PSTART (8*MB) /* start allocating here */ +#define PEND (100*MB) /* below stack */ + +static ulong palloc = PSTART; + +void* +ialloc(ulong n, int align) +{ + ulong p; + int a; + + assert(palloc >= PSTART); + p = palloc; + if(align <= 0) + align = 4; + if(a = n % align) + n += align - a; + if(a = p % align) + p += align - a; + + palloc = p+n; + if(palloc > PEND) + panic("ialloc(%lud, %d) called from %#p", + n, align, getcallerpc(&n)); + return memset((void*)p, 0, n); +} + +void* +xspanalloc(ulong size, int align, ulong span) +{ + ulong a, v; + + if((palloc + (size+align+span)) > PEND) + panic("xspanalloc(%lud, %d, 0x%lux) called from %#p", + size, align, span, getcallerpc(&size)); + + a = (ulong)ialloc(size+align+span, 0); + + if(span > 2) + v = (a + span) & ~(span-1); + else + v = a; + + if(align > 1) + v = (v + align) & ~(align-1); + + return (void*)v; +} + +static Block *allocbp; + +Block* +allocb(int size) +{ + Block *bp, **lbp; + ulong addr; + + lbp = &allocbp; + for(bp = *lbp; bp; bp = bp->next){ + if((bp->lim - bp->base) >= size){ + *lbp = bp->next; + break; + } + lbp = &bp->next; + } + if(bp == 0){ + if((palloc + (sizeof(Block)+size+64)) > PEND) + panic("allocb(%d) called from %#p", + size, getcallerpc(&size)); + bp = ialloc(sizeof(Block)+size+64, 0); + addr = (ulong)bp; + addr = ROUNDUP(addr + sizeof(Block), 8); + bp->base = (uchar*)addr; + bp->lim = ((uchar*)bp) + sizeof(Block)+size+64; + } + + if(bp->flag) + panic("allocb reuse"); + + bp->rp = bp->base; + bp->wp = bp->rp; + bp->next = 0; + bp->flag = 1; + + return bp; +} + +void +freeb(Block* bp) +{ + bp->next = allocbp; + allocbp = bp; + + bp->flag = 0; +} + +void (*etherdetach)(void); + +void +warp9(ulong entry) +{ + ulong inst; + ulong *mem; + + if(etherdetach) + etherdetach(); +// consdrain(); + delay(10); + + splhi(); + trapdisable(); + coherence(); + syncall(); + + qtmerrtest("syncs before kernel entry"); + syncall(); + putmsr(getmsr() & ~MSR_ME); /* disable machine check traps */ + syncall(); + clrmchk(); + syncall(); + + mem = (ulong *)PADDR(entry); + inst = *mem; + if (inst == 0) + panic("word at entry addr is zero, kernel not loaded"); + /* + * This is where to push things on the stack to + * boot *BSD systems, e.g. + * (*((void (*)(void*, void*, void*, void*, ulong, ulong))PADDR(entry))) + * (0, 0, 0, 0, 8196, 640); + * will enable NetBSD boot (the real memory size needs to + * go in the 5th argument). + */ + coherence(); + syncall(); + (*(void (*)(void))mem)(); + + for (;;) + ; +} diff -Nru /sys/src/boot/vt4/malloc.c /sys/src/boot/vt4/malloc.c --- /sys/src/boot/vt4/malloc.c Thu Jan 1 00:00:00 1970 +++ /sys/src/boot/vt4/malloc.c Fri Jun 7 00:00:00 2013 @@ -0,0 +1,76 @@ +/* simple memory allocation */ +#include "include.h" + +#undef malloc +#undef free + +void * +malloc(ulong n) +{ + return ialloc(n, 8); +} + +void +free(void *) +{ +} + +void* +mallocz(ulong size, int clr) +{ + void *v; + + v = malloc(size); + if(clr && v != nil) + memset(v, 0, size); + return v; +} + +void* +realloc(void *v, ulong size) +{ + USED(v, size); + panic("realloc called"); + return 0; +} + +void* +calloc(ulong n, ulong szelem) +{ + return mallocz(n * szelem, 1); +} + +void +setmalloctag(void *v, ulong pc) +{ + USED(v, pc); +} + +void +setrealloctag(void *v, ulong pc) +{ + USED(v, pc); +} + +ulong +getmalloctag(void *v) +{ + USED(v); + assert(0); + return ~0; +} + +ulong +getrealloctag(void *v) +{ + USED(v); + assert(0); + return ~0; +} + +void* +malloctopoolblock(void *v) +{ + USED(v); + return nil; +} diff -Nru /sys/src/boot/vt4/mem.h /sys/src/boot/vt4/mem.h --- /sys/src/boot/vt4/mem.h Thu Jan 1 00:00:00 1970 +++ /sys/src/boot/vt4/mem.h Fri Jun 7 00:00:00 2013 @@ -0,0 +1,196 @@ +/* + * 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 */ + +#define HOWMANY(x, y) (((x)+((y)-1))/(y)) +#define ROUNDUP(x, y) (HOWMANY((x), (y))*(y)) +#define ROUNDDN(x, y) (((x)/(y))*(y)) +#define MIN(a, b) ((a) < (b)? (a): (b)) +#define MAX(a, b) ((a) > (b)? (a): (b)) + +/* + * Sizes + */ +#define BI2BY 8 /* bits per byte */ +#define BY2V 8 /* bytes per vlong */ +#define BY2SE 4 /* bytes per stack element */ +#define BY2WD 4 /* bytes per int */ +#define BY2PG 4096 /* bytes per page */ +#define PGSHIFT 12 /* log(BY2PG) */ +#define PGROUND(s) ROUNDUP(s, BY2PG) +#define UTROUND(t) ROUNDUP((t), 0x100000) +#define STACKALIGN(sp) ((sp) & ~7) /* bug: assure with alloc */ + +#define ICACHESIZE 16384 /* 0, 4, 8, 16, or 32 KB */ +#define ICACHEWAYSIZE (ICACHESIZE/2) /* 2-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<<7) +#define TLB4K (1<<7) +#define TLB16K (2<<7) +#define TLB64K (3<<7) +#define TLB256K (4<<7) +#define TLB1MB (5<<7) +#define TLB4MB (6<<7) +#define TLB16MB (7<<7) +#define TLBVALID (1<<6) +#define TLBLE (1<<5) /* little-endian */ +#define TLBU0 (1<<4) /* user-defined attribute */ + +/* TLBLO */ +#define TLBRPN(x) ((x) & ~0x3FF) +#define TLBEX (1<<9) /* execute enable */ +#define TLBWR (1<<8) /* write enable */ +#define TLBZONE(x) ((x)<<4) +#define TLBW (1<<3) /* write-through */ +#define TLBI (1<<2) /* cache inhibit */ +#define TLBM (1<<1) /* memory coherent */ +#define TLBG (1<<0) /* guarded */ + +/* + * software TLB (for quick reload by [id]tlbmiss) + */ +#define STLBLOG 10 +#define STLBSIZE (1< ]+,/{ + tab = "\t"; + if(length($1) < 8) + sep = tab tab; + else + sep = tab; + split($3, a, ","); + printf "#define %s%s%s", $1, sep, a[1]; + if(match($0, /\/\*.*\*\/$/)){ + len = length(a[1]); + sep = ""; + while(len < 24){ + sep = sep tab; + len += 8; + } + printf "%s%s", sep, substr($0, RSTART); + } + printf "\n" +} + +/^$/{ + printf "\n"; +} + +END{ +}' $* diff -Nru /sys/src/boot/vt4/mkfile /sys/src/boot/vt4/mkfile --- /sys/src/boot/vt4/mkfile Thu Jan 1 00:00:00 1970 +++ /sys/src/boot/vt4/mkfile Fri Jun 7 00:00:00 2013 @@ -0,0 +1,56 @@ +CONF=virtex4 +CONFLIST=virtex4 +BASE=0xfffe2100 # first location after vectors; see PHYSSRAM + +objtype=power +$target.list + $LD -o $target -l -T$BASE -R4 $OBJ $LIB + size $target + nm -n $target | tail -5 + nm -n $target >$target.names + +$OBJ: $HFILES + +${objtype}a.h:D: $objtype.h + rc mkenum $objtype.h > $target + +install:V: $p$CONF + cp -x $p$CONF $p$CONF.elf /power + { 9fs lookout && cp -x $p$CONF $p$CONF.elf /n/lookout/power } & + { 9fs piestand && cp -x $p$CONF $p$CONF.elf /n/piestand/power } & + { 9fs slocum && + cp $p$CONF^* /n/slocum/home/rae/hbsr/ml410_ddr2 && + cp $p$CONF^* /n/slocum/home/rae/hbsr/ml410_qtm } & + wait + +nuke clean:V: + rm -f *.[$OS] *.out *.acid *.elf $p$CONF^* diff -Nru /sys/src/boot/vt4/mkfilelist /sys/src/boot/vt4/mkfilelist --- /sys/src/boot/vt4/mkfilelist Thu Jan 1 00:00:00 1970 +++ /sys/src/boot/vt4/mkfilelist Fri Jun 7 00:00:00 2013 @@ -0,0 +1,12 @@ +#!/bin/rc + +rfork e +switch($#*){ +case 1 + RE=`{echo *.c | sed 's/ /|/g; s/.*/^(&)$/'} + LIST=`{builtin cd $1; ls *.c | grep -v ''$RE''} + echo $LIST | sed 's/\.c//g; s/ +/|/g' +case * + exit 'usage' +} +exit '' diff -Nru /sys/src/boot/vt4/nolock.c /sys/src/boot/vt4/nolock.c --- /sys/src/boot/vt4/nolock.c Thu Jan 1 00:00:00 1970 +++ /sys/src/boot/vt4/nolock.c Fri Jun 7 00:00:00 2013 @@ -0,0 +1,18 @@ +#include "include.h" + +void +lock(Lock* l) +{ + for(;;){ + while(l->key) + ; + if(TAS(&l->key) == 0) + return; + } +} + +void +unlock(Lock* l) +{ + l->key = 0; +} diff -Nru /sys/src/boot/vt4/parse /sys/src/boot/vt4/parse --- /sys/src/boot/vt4/parse Thu Jan 1 00:00:00 1970 +++ /sys/src/boot/vt4/parse Fri Jun 7 00:00:00 2013 @@ -0,0 +1,536 @@ +BEGIN{ + oargc = 0; + for(argc = 1; argc < ARGC; argc++){ + if(ARGV[argc] !~ /^-.+/ || ARGV[argc] ~ /--/) + break; + if(ARGV[argc] != "-D") + oargv[ARGV[argc]] = oargc++; + else + DEBUG = 1; + ARGV[argc] = ""; + } + + objtype = ENVIRON["objtype"]; + + while(getline > 0){ + if(/^[ \t]*$/ || /^#/) + continue; + + if(/^[^ \t]/){ + #section[$1] = 0; + tag = $1; + } + if(!tag) + continue; + sub(/^[ \t]*/, ""); + line[tag, section[tag]++] = $0; + } + + o = ""; + if(!oargc || ("-mkdevlist" in oargv)){ + s = mkdevlist(); + if(!("-mkdevlist" in oargv) || (oargc > 1)) + s = "DEVS=" s; + o = o s "\n"; + } + if((!oargc || ("-mkmach" in oargv)) && (objtype in section)){ + s = mkmach(); + if(!("-mkmach" in oargv) || (oargc > 1)) + s = "MACH=" s; + o = o s "\n"; + } + if((!oargc || ("-mklib" in oargv)) && ("lib" in section)){ + s = mklib(); + if(!("-mklib" in oargv) || (oargc > 1)) + s = "LIB=" s; + o = o s "\n"; + } + if((!oargc || ("-mkport" in oargv) ) && ("port" in section)){ + s = mkport(); + if(!("-mkport" in oargv) || (oargc > 1)) + s = "PORT=" s; + o = o s "\n"; + } + if("dbgflg" in section){ + for(i = 1; i < section["dbgflg"]; i++){ + n = split(line["dbgflg", i], a); + if(n < 2 || n > 4 || a[2] !~ /'[a-zA-Z]'/) + continue; + if(n > 2 && a[3] !~ /'[a-zA-Z]'/) + continue; + if(n == 4 && (a[4] < 1 || a[4] >= 128)) + continue; + dbgc[a[1]] = a[2]; + if(n == 4) + dbgflg[a[3]] = a[4]; + else if(n == 3) + dbgflg[a[3]] = 1; + } + } + if((!oargc || ("-mkrules" in oargv)) && ("dir" in section)){ + o = o mkrules(".", exists, a, c, "-I."); + for(i = 1; i < section["dir"]; i++){ + n = split(line["dir", i], a); + dir = "../" a[1]; + if(n == 1) + a[2] = "-I."; + s = a[2]; + o = o mkrules(dir, exists, a, c, s); + l = listolate(a, "|"); + if(l != ""){ + o = o "^(" l ")\\.$O:R: " dir "/\\1.s\n"; + o = o "\t$AS $AFLAGS " s " " dir "/$stem1.s\n"; + } + l = listolate(c, "|"); + if(l != ""){ + o = o "^(" l ")\\.$O:R: " dir "/\\1.c\n"; + o = o "\t$CC $CFLAGS " s " " dir "/$stem1.c\n"; + } + } + } + if((!oargc || ("-mkrootrules" in oargv)) && ("rootdir" in section)){ + mkrootrules(name, cname, src); + s = ARGV[argc] ".root.s:D:"; + for(i = 1; i < section["rootdir"]; i++) + s = s " " src[i]; + s = s "\n\tmkrootall\\\n"; + for(i = 1; i < section["rootdir"]; i++) + s = s "\t\t" name[i] " " cname[i] " " src[i] "\\\n"; + s = s "\t>$target\n"; + if(section["rootdir"] > 1) + o = o s; + } + if((!oargc || ("-mkrrrules" in oargv)) && ("rr" in section)){ + n = split(line["rr", 0], a); + if(n == 1) + a[2] = ARGV[argc] ".proto"; + s = "$CONF.rr:\tmkrr $CONF " a[2] "\n"; + s = s "\tmkrr $CONF " a[2] "\n"; + for(i = 1; i < section["rr"]; i++) + s = s "$CONF.rr:\t" line["rr", i] "\n"; + o = o s; + } + if("-mkdevc" in oargv) + o = o mkdevc(); + if("-mkerrstr" in oargv) + o = o mkerrstr(); + if("-mksystab" in oargv) + o = o mksystab(); + if("-mkbootconf" in oargv) + o = o mkbootconf(); + + # + # to do: + # bootmkfile + # mkrootall (can it be done at all?) + # + printf o; + + exit 0; +} + +function mkbootconf( a, n, s, t, u, c, d, p, r){ + s = "#include \n"; + s = s "#include \n\n"; + s = s "#include \"../boot/boot.h\"\n\n"; + s = s "Method method[] = {\n"; + + c = "0"; + d = "#S/sdC0/"; + p = "boot"; + r = "/root"; + + for(i = 0; i < section["boot"]; i++){ # NOTE: start at 0 + n = split(line["boot", i], a); + if(a[1] == "boot"){ + if(a[2] == "cpu"){ + c = "1"; + if(n == 4 && a[3] == "boot") + d = a[4]; + } + else if(a[2] == "rootdir" && n == 3) + r = a[3]; + else if(a[2] ~ /^(bboot|dosboot|romboot)$/){ + c = "1"; + p = a[2]; + } + else if(a[2] == "boot" && n == 3) + d = a[3]; + continue; + } + s = s "\t{ \"" a[1] "\", config" a[1] ", connect" a[1] ", "; + t = "nil"; + if(n > 1){ + u = line["boot", i]; + if(sub(/^[_A-Za-z][_A-Za-z0-9]*[ \t]*/, "", u)){ + if(match(u, /^".*"$/)) + u = substr(u, RSTART+1, RLENGTH-2); + t = "\"" u "\""; + } + } + s = s t ", },\n"; + } + s = s "\t{ nil },\n};\n\n"; + s = s "int cpuflag = " c ";\n"; + s = s "char* rootdir = \"" r "\";\n"; + s = s "char* bootdisk = \"" d "\";\n"; + s = s "extern void " p "(int, char**);\n\n"; + s = s "void\nmain(int argc, char **argv)\n"; + s = s "{\n\t" p "(argc, argv);\n}\n" + + t = "int (*cfs)(int) = 0;\n"; + for(i = 1; i < section["rootdir"]; i++){ + if($1 !~ /\/bin\/cfs$/) + continue; + t = "int (*cfs)(int) = cache;\n"; + break; + } + s = s t; + + return s; +} + +function mksystab( a, i, f, n, s, t){ + s = "#include \"/sys/src/libc/9syscall/sys.h\"\n\n"; + s = s "typedef void Syscall(Ar0*, va_list);\n\n"; + + t = ""; + while(getline < "/sys/src/libc/9syscall/sys.h"){ + if($1 != "#define" || NF != 3) + continue; + + f = "sys" tolower($2); + if($2 == "SYSR1") + f = "sysr1"; + if($2 == "RENDEZVOUS") + n = "Rendez"; + else if($2 == "BRK_") + n = "Brk"; + else + n = substr($2, 1, 1) tolower(substr($2, 2)); + + s = s "Syscall " f ";\n"; + t = t "\t[" $2 "]\t"; + if(length($2) < 6) + t = t "\t"; + t = t "{ \"" n "\", " f ", "; + # + # if($1 ~ "(FVERSION|FSTAT|STAT)") + # t = t "{ .u = 0 } },\n"; + # else + # + if($1 ~ "(BIND|MOUNT|FWSTAT|WSTAT)") + t = t "{ .l = 0 } },\n"; + else if($1 ~ "(EXEC|RENDEZVOUS|SEGBRK|SEGATTACH)") + t = t "{ .v = (void*)-1 } },\n"; + else + t = t "{ .i = -1 } },\n"; + } + if("syscall" in section){ + for(i = 1; i < section["syscall"]; i++){ + if(split(line["syscall", i], a) != 8) + continue; + if(line["syscall", i] !~ /#define.*{ \.[ilpuv] = .* }$/) + continue; + + f = "sys" tolower(a[2]); + n = substr(a[2], 1, 1) tolower(substr(a[2], 2)); + + s = s "\nSyscall " f ";\n"; + t = t a[1] " " a[2] "\t" a[3] "\n\t[" a[2] "]\t"; + if(length(a[2]) < 6) + t = t "\t"; + split(line["syscall", i], a, "{"); + t = t "{ \"" n "\", " f ", {" a[2] " },\n"; + } + } + s = s "struct {\n\tchar*\tn;\n\tSyscall*f;\n\tAr0\tr;\n}"; + s = s " systab[] = {\n" t "};\n\nint nsyscall = nelem(systab);\n"; + + return s; +} + +function mkerrstr( a, s){ + FS="[ \t;]+"; + while(getline < "error.h"){ + split($0, a, /\/\* | \*\//); + s = s $2 " " $3 " = \"" a[2] "\";\n"; + } + FS=" "; + + return s; +} + +function mkdevc( a, d, i, m, n, s, t, u, name, cname){ + s = "#include \"u.h\"\n"; + s = s "#include \"lib.h\"\n"; + s = s "#include \"mem.h\"\n"; + s = s "#include \"dat.h\"\n"; + s = s "#include \"fns.h\"\n"; + s = s "#include \"error.h\"\n\n"; + s = s "#include \"io.h\"\n\n"; + + t = ""; + for(i = 1; i < section["dev"]; i++){ + split(line["dev", i], a); + s = s "extern Dev " a[1] "devtab;\n"; + t = t "\t&" a[1] "devtab,\n"; + d[a[1]]++; + } + s = s "Dev* devtab[] = {\n" t "\tnil,\n};\n\n"; + + mkrootrules(name, cname, m); + t = ""; + for(i = 1; i < section["rootdir"]; i++){ + s = s "extern uchar " cname[i] "code[];\n"; + s = s "extern usize " cname[i] "len;\n"; + t = t "\taddbootfile(\"" name[i] "\", " cname[i] "code, " cname[i] "len);\n"; + } + for(i = 1; i < section["link"]; i++){ + split(line["link", i], a); + s = s "extern void " a[1] "link(void);\n"; + t = t "\t" a[1] "link();\n"; + } + s = s "void\nlinks(void)\n{\n" t "}\n\n"; + + if("ip" in d && "ip" in section){ + t = ""; + s = s "#include \"../ip/ip.h\"\n"; + for(i = 1; i < section["ip"]; i++){ + split(line["ip", i], a); + s = s "extern void " a[1] "init(Fs*);\n"; + t = t "\t" a[1] "init,\n"; + } + s = s "void (*ipprotoinit[])(Fs*) = {\n" t "\tnil,\n};\n\n"; + } + + if("sd" in d && "sd" in section){ + t = ""; + s = s "#include \"sd.h\"\n"; + for(i = 1; i < section["sd"]; i++){ + split(line["sd", i], a); + s = s "extern SDifc " a[1] "ifc;\n"; + t = t "\t&" a[1] "ifc,\n"; + } + s = s "SDifc* sdifc[] = {\n" t "\tnil,\n};\n\n"; + } + + if("uart" in d && "uart" in section){ + t = ""; + for(i = 1; i < section["uart"]; i++){ + split(line["uart", i], a); + a[1] = substr(a[1], 5, length(a[1])-4) "physuart"; + s = s "extern PhysUart " a[1] ";\n"; + t = t "\t&" a[1] ",\n"; + } + s = s "PhysUart* physuart[] = {\n" t "\tnil,\n};\n\n"; + } + + t = ""; + n = 0; + if("physseg" in section){ + for(i = 1; i < section["physseg"]; i++){ + u = line["physseg", i]; + if(u ~ /^\.[_A-Za-z][_A-Za-z0-9]*/) + t = t "\t"; + t = t "\t" u "\n"; + if(sub(/.*\.pgalloc.*=[^_A-Za-z]*/, "", u)){ + if(match(u, /^[_A-Za-z][_A-Za-z0-9]*/)){ + u = substr(u, RSTART, RLENGTH); + s = s "extern Page *(*" u ")(Segment*, uintptr);\n"; + } + } + else if(sub(/.*\.pgfree.*=[^_A-Za-z]*/, "", u)){ + if(match(u, /^[_A-Za-z][_A-Za-z0-9]*/)){ + u = substr(u, RSTART, RLENGTH); + s = s "extern void (*" u ")(Page*);\n"; + } + } + if(match(u, /}/)) + n++; + } + } + s = s "Physseg physseg[" n+8 "] = {\n"; + s = s "\t{\t.attr\t= SG_SHARED,\n"; + s = s "\t\t.name\t= \"shared\",\n"; + s = s "\t\t.size\t= SEGMAXSIZE,\n\t},\n"; + s = s "\t{\t.attr\t= SG_BSS,\n"; + s = s "\t\t.name\t= \"memory\",\n"; + s = s "\t\t.size\t= SEGMAXSIZE,\n\t},\n"; + s = s t "};\nint nphysseg = " n+8 ";\n\n"; + + s = s "char dbgflg[256]"; + t = ""; + for(u in dbgflg) + t = t "\t[" u "]\t" dbgflg[u] ",\n"; + if(t != "") + s = s " = {\n" t "}"; + s = s ";\n\n"; + + for(i in m) + delete m[i]; + + for(i = 1; i < section["misc"]; i++){ + split(line["misc", i], a); + m[a[1]] = line["misc", i]; + } + if("cache" in m){ + s = s "extern void cinit(void);\n"; + s = s "extern void copen(Chan*);\n"; + s = s "extern int cread(Chan*, uchar*, int, vlong);\n"; + s = s "extern void cupdate(Chan*, uchar*, int, vlong);\n"; + s = s "extern void cwrite(Chan*, uchar*, int, vlong);\n\n"; + s = s "void (*mfcinit)(void) = cinit;\n"; + s = s "void (*mfcopen)(Chan*) = copen;\n"; + s = s "int (*mfcread)(Chan*, uchar*, int, vlong) = cread;\n"; + s = s "void (*mfcupdate)(Chan*, uchar*, int, vlong) = cupdate;\n"; + s = s "void (*mfcwrite)(Chan*, uchar*, int, vlong) = cwrite;\n\n"; + } + else{ + s = s "void (*mfcinit)(void) = nil;\n"; + s = s "void (*mfcopen)(Chan*) = nil;\n"; + s = s "int (*mfcread)(Chan*, uchar*, int, vlong) = nil;\n"; + s = s "void (*mfcupdate)(Chan*, uchar*, int, vlong) = nil;\n"; + s = s "void (*mfcwrite)(Chan*, uchar*, int, vlong) = nil;\n\n"; + } + if(!("rdb" in misc)){ + s = s "void\n"; + s = s "rdb(void)\n"; + s = s "{\n"; + s = s "\tsplhi();\n"; + s = s "\tiprint(\"rdb...not installed\\n\");\n"; + s = s "\tfor(;;);\n"; + s = s "}\n\n"; + } + + if("conf" in section){ + for(i = 1; i < section["conf"]; i++) + s = s line["conf", i] "\n"; + s = s "\n"; + } + t = "."; + while("pwd" | getline > 0){ + if($0 ~ /^\//) + t = $0; + } + s = s "char* conffile = \"" t "/" ARGV[argc] "\";\n"; + s = s "ulong kerndate = KERNDATE;\n"; + + return s; +} + +function mkrootrules(name, cname, src, a, i, n){ + for(i = 1; i < section["rootdir"]; i++){ + n = split(line["rootdir", i], a); + if(n >= 2) + name[i] = a[2]; + else + name[i] = a[1]; + sub(/.*\//, "", name[i]); + cname[i] = a[1]; + gsub(/[^a-zA-Z0-9_]/, "_", cname[i]); + src[i] = a[1]; + } +} + +function mkrules(dir, exists, ameta, cmeta, flags, f, i, s, t){ + for(i in ameta) + delete ameta[i]; + for(i in cmeta) + delete cmeta[i]; + + s = ""; + while("cd " dir "; /bin/ls *.[cs]" | getline > 0){ + if($0 !~ /^[A-Za-z0-9]*\.[cs]$/) + continue; + f = $0; + if(!sub(/\.[cs]$/, "")) + continue; + if($0 in exists) + continue; + exists[$0] = dir; + if(f ~ /\.c$/){ + if(!($0 in dbgc)){ + cmeta[$0]++; + continue; + } + t = "$CC $CFLAGS " flags; + } + else{ + if(!($0 in dbgc)){ + ameta[$0]++; + continue; + } + t = "$AS $AFLAGS " flags; + } + s = s $0 ".$O:\t" dir "/" f "\n"; + s = s "\t" t " -D'_DBGC_='" dbgc[$0] "'' " dir "/" f "\n"; + } + return s; +} + +function mkport( array){ + arrayify(array, "port", "", ".$O", 1); + + return listolate(array, " "); +} + +function mklib( array){ + arrayify(array, "lib", "/$objtype/lib/", ".a", 1); + + return listolate(array," "); +} + +function mkmach( a, i, s){ + s = ""; + for(i = 1; i < section[objtype]; i++){ + if(!split(line[objtype, i], a)) + continue; + if(s == "") + s = a[1] ".$O"; + else + s = s " " a[1] ".$O"; + } + + return s; +} + +function mkdevlist( a, array, i, j, n, s){ + for(s in section){ + if(line[s, 0] !~ /[ \t]\+dev[^_A-Za-z0-9]*/) + continue; + if(s == "dev") + arrayify(array, s, "dev", ".$O", 1); + else if(s == objtype) + arrayify(array, s, "", ".$O", 0); + else + arrayify(array, s, "", ".$O", 1); + } + + return listolate(array, " "); +} + +function listolate(array, sep, a, s){ + s = ""; + for(a in array){ + if(s == "") + s = a; + else + s = a sep s; + } + + return s; +} + +function arrayify(array, tag, prefix, suffix, one, a, i, j, n){ + for(i = 1; i < section[tag]; i++){ + n = split(line[tag, i], a); + if(one) + array[prefix a[1] suffix]++; + for(j = 2; j <= n; j++){ + if(a[$j] ~ /[+=-].*/) + continue; + array[a[j] suffix]++; + } + } +} diff -Nru /sys/src/boot/vt4/physmem.h /sys/src/boot/vt4/physmem.h --- /sys/src/boot/vt4/physmem.h Thu Jan 1 00:00:00 1970 +++ /sys/src/boot/vt4/physmem.h Fri Jun 7 00:00:00 2013 @@ -0,0 +1,33 @@ +/* + * Memory-mapped IO + */ + +/* + * virtex4 system loses top 1/9th of 128MB to ECC in the secure memory system. + * if the mac boundary is not a cache-line boundary (multiple of 32), + * don't touch anything in the last cache-line (round mac boundary down + * to a multiple of 32). MEMTOP computes the first untouchable address. + */ +#define MEMTOP(phys) (((((phys)/DCACHELINESZ)*8)/9) * DCACHELINESZ) +#define MAXMEM (128*MB) + +/* memory map for rae's virtex4 design */ +#define PHYSDRAM 0 +#define PHYSSRAM 0xfffe0000 /* 128K long, in top 128M */ + +#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 */ diff -Nru /sys/src/boot/vt4/portclock.c /sys/src/boot/vt4/portclock.c --- /sys/src/boot/vt4/portclock.c Thu Jan 1 00:00:00 1970 +++ /sys/src/boot/vt4/portclock.c Fri Jun 7 00:00:00 2013 @@ -0,0 +1,23 @@ +/* portable clock code */ +#include "include.h" + +ulong intrcount[MAXMACH]; + +void +hzclock(void) +{ + m->ticks++; + dcflush(PTR2UINT(&m->ticks), sizeof m->ticks); +} + +void +timerintr(Ureg *) +{ + intrcount[m->machno]++; + hzclock(); +} + +void +timersinit(void) +{ +} diff -Nru /sys/src/boot/vt4/portmkfile /sys/src/boot/vt4/portmkfile --- /sys/src/boot/vt4/portmkfile Thu Jan 1 00:00:00 1970 +++ /sys/src/boot/vt4/portmkfile Fri Jun 7 00:00:00 2013 @@ -0,0 +1,16 @@ +%.$O: %.s + $AS $AFLAGS $stem.s + +%.$O: %.c + $CC $CFLAGS $stem.c + +%.$O: include.h +%.$O: /$objtype/include/u.h +%.$O: libc.h +%.$O: define.h +%.$O: data.h portdata.h +%.$O: prototype.h portprototype.h +%.$O: glue.h + +clean:V: + rm -f *.[$OS] *.out *.m *.acid $p$CONF *.elf diff -Nru /sys/src/boot/vt4/portprototype.h /sys/src/boot/vt4/portprototype.h --- /sys/src/boot/vt4/portprototype.h Thu Jan 1 00:00:00 1970 +++ /sys/src/boot/vt4/portprototype.h Fri Jun 7 00:00:00 2013 @@ -0,0 +1,2 @@ +extern void ilock(Lock*); +extern void iunlock(Lock*); diff -Nru /sys/src/boot/vt4/ppc405.h /sys/src/boot/vt4/ppc405.h --- /sys/src/boot/vt4/ppc405.h Thu Jan 1 00:00:00 1970 +++ /sys/src/boot/vt4/ppc405.h Fri Jun 7 00:00:00 2013 @@ -0,0 +1,64 @@ +/* + * PowerPC 405 definitions + */ +#include "mem.h" + +#undef PGROUND +#define PGROUND(s) ROUNDUP(s, MiB) + +/* + * Special Purpose Registers of interest here + */ + +#define SPR_SRR0 26 /* Save/Restore Register 0 */ +#define SPR_SRR1 27 /* Save/Restore Register 1 */ +#define SPR_TBU 85 /* Time Base Upper */ +#define SPR_SPRG0 272 /* SPR General 0 */ +#define SPR_SPRG1 273 /* SPR General 1 */ +#define SPR_SPRG2 274 /* SPR General 2 */ +#define SPR_SPRG3 275 /* SPR General 3 */ +#define SPR_TBL 284 /* Time Base Lower */ +#define SPR_PVR 287 /* Processor Version */ +#define SPR_IVOR(n) (400+(n)) /* Interrupt Vector Offset 0-15 */ +#define SPR_ZPR 944 /* Zone Protection Register */ +#define SPR_PID 945 /* Process Identity */ +#define SPR_MMUCR 946 /* MMU Control */ +#define SPR_CCR0 947 /* Core Configuration Register 0 */ +#define SPR_IAC3 948 /* Instruction Address Compare 3 */ +#define SPR_IAC4 949 /* Instruction Address Compare 4 */ +#define SPR_DVC1 950 /* Data Value Compare 1 */ +#define SPR_DVC2 951 /* Data Value Compare 2 */ +#define SPR_SGR 953 /* Store Guarded Register */ +#define SPR_DCWR 954 /* Data Cache Write-through Register */ +#define SPR_SLER 955 /* Storage Little Endian Register */ +#define SPR_SU0R 956 /* Storage User-defined 0 Register */ +#define SPR_DBCR1 957 /* Debug Control Register 1 */ +#define SPR_ICDBDR 979 /* Instruction Cache Debug Data Register */ +#define SPR_ESR 980 /* Exception Syndrome Register */ +#define SPR_DEAR 981 /* Data Error Address Register */ +#define SPR_EVPR 982 /* Exception Vector Prefix Register */ +#define SPR_TSR 984 /* Time Status Register */ +#define SPR_TCR 986 /* Time Control Register */ +#define SPR_PIT 987 /* Programmable Interval Timer */ +#define SPR_SRR2 990 /* Save/Restore Register 2 */ +#define SPR_SRR3 991 /* Save/Restore Register 3 */ +#define SPR_DBSR 1008 /* Debug Status Register */ +#define SPR_DBCR0 1010 /* Debug Control Register 0 */ +#define SPR_IAC1 1012 /* Instruction Address Compare 1 */ +#define SPR_IAC2 1013 /* Instruction Address Compare 2 */ +#define SPR_DAC1 1014 /* Data Address Compare 1 */ +#define SPR_DAC2 1015 /* Data Address Compare 2 */ +#define SPR_DCCR 1018 /* Data Cache Cachability Register */ +#define SPR_ICCR 1019 /* Instruction Cache Cachability Register */ + +/* + * Bit encodings for Memory Management Unit Control Register (MMUCR) + */ +#define MMUCR_STS 0x00010000 /* search translation space */ +#define MMUCR_IULXE 0x00040000 /* instruction cache unlock exception enable */ +#define MMUCR_DULXE 0x00080000 /* data cache unlock exception enable */ +#define MMUCR_U3L2SWOAE 0x00100000 /* U3 L3 store without allocate enable */ +#define MMUCR_U2SWOAE 0x00200000 /* U2 store without allocate enable */ +#define MMUCR_U1TE 0x00400000 /* U1 transient enable */ +#define MMUCR_SWOA 0x01000000 /* store without allocate */ +#define MMUCR_L2SWOA 0x02000000 /* L2 store without allocate */ diff -Nru /sys/src/boot/vt4/print.c /sys/src/boot/vt4/print.c --- /sys/src/boot/vt4/print.c Thu Jan 1 00:00:00 1970 +++ /sys/src/boot/vt4/print.c Fri Jun 7 00:00:00 2013 @@ -0,0 +1,38 @@ +#include "include.h" + +int +print(char* fmt, ...) +{ + int n; + va_list args; + char buf[PRINTSIZE]; + + va_start(args, fmt); + n = vseprint(buf, buf+sizeof(buf), fmt, args) - buf; + va_end(args); + + vuartputs(buf, n); + return n; +} + +void +_fmtlock(void) +{ +} + +void +_fmtunlock(void) +{ +} + +int +_efgfmt(Fmt*) +{ + return -1; +} + +int +errfmt(Fmt*) +{ + return -1; +} diff -Nru /sys/src/boot/vt4/prototype.h /sys/src/boot/vt4/prototype.h --- /sys/src/boot/vt4/prototype.h Thu Jan 1 00:00:00 1970 +++ /sys/src/boot/vt4/prototype.h Fri Jun 7 00:00:00 2013 @@ -0,0 +1,196 @@ +#define PTR2UINT(p) ((uintptr)(p)) +#define UINT2PTR(i) ((void*)(i)) + +/* physical == virtual in our world! */ +#define PADDR(a) ((ulong)(a) & ~0xF0000000) + +#define GSHORT(p) (((p)[1]<<8)|(p)[0]) +#define GLONG(p) ((GSHORT(p+2)<<16)|GSHORT(p)) +#define GLSHORT(p) (((p)[0]<<8)|(p)[1]) +#define GLLONG(p) (((ulong)GLSHORT(p)<<16)|GLSHORT(p+2)) +#define PLLONG(p,v) (p)[3]=(v);(p)[2]=(v)>>8;(p)[1]=(v)>>16;(p)[0]=(v)>>24 + +#define mallocalign(n, a, o, s) ialloc((n), (a)) + +/* emergency debugging printing, from uart.c */ +#define Uarttxfifo ((ulong *)(Uartlite + 4)) +#define PROG(c) { coherence(); *Uarttxfifo = (uchar)(c); coherence(); } + +/* + * l32p.s + */ +void cachesinvalidate(void); +void dcbi(void*); +void dcflush(uintptr, usize); +void eieio(void); +u32int esrget(void); +void esrput(u32int); +// char* getconf(char*); +#define getconf(s) nil +u32int getccr0(void); +u32int getdar(void); +u32int getdear(void); +u32int getdec(void); +u32int getesr(void); +u32int getmsr(void); +u32int getpid(void); +u32int getpir(void); +u32int getpit(void); +u32int getpvr(void); +u32int gettbl(void); +u32int gettsr(void); +void icflush(uintptr, usize); +int islo(void); +void microdelay(int); +u32int mmucrget(void); +void mmucrput(u32int); +void putdec(ulong); +void putesr(ulong); +void putevpr(ulong); +void putmsr(u32int); +void putpid(u32int); +void putpit(u32int); +void putsdr1(u32int); +void puttcr(u32int); +void puttsr(u32int); +void setsp(uintptr); +void spldone(void); +int splhi(void); +int spllo(void); +void splx(int); +void splxpc(int); +void sync(void); +void syncall(void); +int tas32(uint*); +void trapvec(void); +int _xdec(long *); +int _xinc(long *); + +/* + * trap.c + */ +void trapdisable(void); +void trapinit(void); + +/* + * intr.c + */ +void intr(Ureg *ur); +void intrack(ulong); +void intrenable(ulong bit, int (*func)(ulong)); +void intrinit(void); +ulong lddbg(void); + +/* + * uart.c + */ +int vuartgetc(void); +void vuartputc(int c); +int vuartputs(char *s, int len); + +/* + * clock.c + */ +void clockinit(void); +void clockintr(Ureg *ureg); +void delay(int); +void prcpuid(void); +void timerintr(Ureg*); + +/* + * dma.c + */ +void dmacpy(void *dest, void *src, ulong len, ulong flags); +void dmainit(void); +void dmastart(void *dest, void *src, ulong len, ulong flags); +void dmawait(void); + +/* + * ether.c + */ +uchar *etheraddr(int ctlrno); +int etherinit(void); +void etherinitdev(int, char*); +void etherprintdevs(int); +int etherrxflush(int ctlrno); +int etherrxpkt(int ctlrno, Etherpkt* pkt, int timo); +int ethertxpkt(int ctlrno, Etherpkt* pkt, int len, int); + +/* + * llfifo.c + */ +void llfifoinit(Ether *); +int llfifointr(ulong bit); +void llfiforeset(void); +void llfifotransmit(uchar *ubuf, unsigned len); + +/* + * load.c + */ +int getfields(char*, char**, int, char); +void* ialloc(ulong, int); + +/* + * boot.c + */ +int bootpass(Boot *b, void *vbuf, int nbuf); + +/* + * bootp.c + */ +int bootpboot(int, char*, Boot*); +void* pxegetfspart(int, char*, int); + +/* + * conf.c + */ +int dotini(Fs *fs); + +/* + * console.c + */ +void consinit(char*, char*); +int getstr(char*, char*, int, char*, int); +void kbdinit(void); +void warp86(char*, ulong); +void warp9(ulong); + +/* + * inflate.c + */ +int gunzip(uchar*, int, uchar*, int); + +/* + * misc. + */ + +void ilock(Lock*); +void iunlock(Lock*); +int lock(Lock*); +void unlock(Lock*); + +void panic(char *fmt, ...); + +#define TAS(l) tas32(l) + +#define iprint print + +#define coherence() eieio() +#define exit(n) for(;;) ; + +void cacheline0(uintptr addr); +ulong cacheson(void); +void clrmchk(void); +void dump(void *, int); +void dumpregs(Ureg *); +void flushwrbufs(void); +uintptr memsize(void); +vlong probeaddr(uintptr addr); +/* + * qtm.c + */ +int qtmerrfmt(char *, int); +void qtmerrtest(char *); +void qtmerrtestaddr(ulong); +int qtmmemreset(void); +vlong qtmprobeaddr(uintptr addr); diff -Nru /sys/src/boot/vt4/taslock.c /sys/src/boot/vt4/taslock.c --- /sys/src/boot/vt4/taslock.c Thu Jan 1 00:00:00 1970 +++ /sys/src/boot/vt4/taslock.c Fri Jun 7 00:00:00 2013 @@ -0,0 +1,210 @@ +#include "include.h" + +#undef LOCKCYCLES + +#ifdef LOCKCYCLES +uvlong maxlockcycles; +uvlong maxilockcycles; +ulong maxlockpc; +ulong maxilockpc; +#endif + +struct +{ + ulong locks; + ulong glare; + ulong inglare; +} lockstats; + +static void +inccnt(Ref *r) +{ + _xinc(&r->ref); +} + +static int +deccnt(Ref *r) +{ + int x; + + x = _xdec(&r->ref); + assert(x >= 0); +// if(x < 0) +// panic("deccnt pc=%#p", getcallerpc(&r)); + return x; +} + +static void +dumplockmem(char *tag, Lock *l) +{ + uchar *cp; + int i; + + iprint("%s: ", tag); + cp = (uchar*)l; + for(i = 0; i < 64; i++) + iprint("%2.2ux ", cp[i]); + iprint("\n"); +} + +void +lockloop(Lock *l, uintptr pc) +{ + print("lock %#p loop key %#ux pc %#p\n", l, l->key, pc); +} + +int +lock(Lock *l) +{ + int i; + uintptr pc; + + pc = getcallerpc(&l); + + lockstats.locks++; + if(TAS(&l->key) == 0){ + l->pc = pc; + l->isilock = 0; +#ifdef LOCKCYCLES + cycles(&l->lockcycles); +#endif + return 0; + } + + lockstats.glare++; + for(;;){ + lockstats.inglare++; + i = 0; + while(l->key){ + if(i++ > 100000000){ + i = 0; + lockloop(l, pc); + } + } + if(TAS(&l->key) == 0){ + l->pc = pc; + l->isilock = 0; +#ifdef LOCKCYCLES + cycles(&l->lockcycles); +#endif + return 1; + } + } +} + +void +ilock(Lock *l) +{ + ulong sr; + uintptr pc; + + pc = getcallerpc(&l); + lockstats.locks++; + + sr = splhi(); + if(TAS(&l->key) != 0){ + lockstats.glare++; + /* + * Cannot also check l->pc and l->m here because + * they might just not be set yet, or the lock might + * even have been let go. + */ + if(!l->isilock){ + dumplockmem("ilock:", l); + print("corrupt ilock %#p pc=%#p m=%#p isilock=%d", + l, l->pc, l->m, l->isilock); + assert(0); + } + if(l->m == MACHP(m->machno)) { + print("ilock: deadlock on cpu%d pc=%#p lockpc=%#p\n", + m->machno, pc, l->pc); + assert(0); + } + for(;;){ + lockstats.inglare++; + splx(sr); + while(l->key) + ; + sr = splhi(); + if(TAS(&l->key) == 0) + goto acquire; + } + } +acquire: +// m->ilockdepth++; + l->sr = sr; + l->pc = pc; + l->isilock = 1; + l->m = MACHP(m->machno); +#ifdef LOCKCYCLES + cycles(&l->lockcycles); +#endif +} + +int +canlock(Lock *l) +{ + if(TAS(&l->key)) + return 0; + + l->pc = getcallerpc(&l); + l->m = MACHP(m->machno); + l->isilock = 0; +#ifdef LOCKCYCLES + cycles(&l->lockcycles); +#endif + return 1; +} + +void +unlock(Lock *l) +{ +#ifdef LOCKCYCLES + uvlong x; + cycles(&x); + l->lockcycles = x - l->lockcycles; + if(l->lockcycles > maxlockcycles){ + maxlockcycles = l->lockcycles; + maxlockpc = l->pc; + } +#endif + + if(l->key == 0) + print("unlock: not locked: pc %#p\n", getcallerpc(&l)); + if(l->isilock) + print("unlock of ilock: pc %#p, held by %#p\n", + getcallerpc(&l), l->pc); + l->m = nil; + l->key = 0; + coherence(); +} + +void +iunlock(Lock *l) +{ + ulong sr; + +#ifdef LOCKCYCLES + uvlong x; + cycles(&x); + l->lockcycles = x - l->lockcycles; + if(l->lockcycles > maxilockcycles){ + maxilockcycles = l->lockcycles; + maxilockpc = l->pc; + } +#endif + + if(l->key == 0) + print("iunlock: not locked: pc %#p\n", getcallerpc(&l)); + if(!l->isilock) + print("iunlock of lock: pc %#p, held by %#p\n", getcallerpc(&l), l->pc); + if(islo()) + print("iunlock while lo: pc %#p, held by %#p\n", getcallerpc(&l), l->pc); + + sr = l->sr; + l->m = nil; + l->key = 0; + coherence(); +// m->ilockdepth--; + splx(sr); +} diff -Nru /sys/src/boot/vt4/trap.c /sys/src/boot/vt4/trap.c --- /sys/src/boot/vt4/trap.c Thu Jan 1 00:00:00 1970 +++ /sys/src/boot/vt4/trap.c Fri Jun 7 00:00:00 2013 @@ -0,0 +1,324 @@ +/* + * power pc 405 traps + */ +#include "include.h" + +static struct { + ulong off; + char *name; +} intcause[] = { + { INT_RESET, "system reset" }, + { 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" }, + { 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; +static jmp_buf probenv; + +static void +sethvec(uintptr v, void (*r)(void)) +{ + u32int *vp; + ulong o, ra; + long d; + + vp = UINT2PTR(v); + vp[0] = 0x7c1043a6; /* MOVW R0, SPR(SPRG0) */ + vp[1] = 0x7c0802a6; /* MOVW LR, R0 */ + vp[2] = 0x7c1243a6; /* MOVW R0, SPR(SPRG2) */ + d = (uchar*)r - (uchar*)&vp[3]; + o = (ulong)d >> 25; + if(o != 0 && o != 0x7F){ + /* a branch too far: running from ROM */ + ra = (ulong)r; + vp[3] = (15<<26)|(ra>>16); /* MOVW $r&~0xFFFF, R0 */ + vp[4] = (24<<26)|(ra&0xFFFF); /* OR $r&0xFFFF, R0 */ + vp[5] = 0x7c0803a6; /* MOVW R0, LR */ + vp[6] = 0x4e800021; /* BL (LR) */ + } + else + vp[3] = (18<<26)|(d&0x3FFFFFC)|1; /* BL (relative) */ + dcflush(PTR2UINT(vp), 8*sizeof(u32int)); +} + +static void +sethvec2(uintptr v, void (*r)(void)) +{ + u32int *vp; + long d; + + vp = UINT2PTR(v); + d = (uchar*)r - (uchar*)&vp[0]; + vp[0] = (18<<26)|(d & 0x3FFFFFC); /* B (relative) */ + dcflush(PTR2UINT(vp), sizeof(*vp)); +} + +extern uintptr vectorbase; + +void +trapinit(void) +{ + uintptr e, s; + + putesr(0); /* clears machine check */ + coherence(); + + /* + * set all exceptions to trap + */ + s = vectorbase + 0x100; /* Mach is at vectorbase */ + /* 0x2000 is last documented 405 vector */ + for(e = s+0x2100; s < e; s += 0x100) + sethvec(s, trapvec); + coherence(); + + /* + * set exception handlers + */ +// sethvec(vectorbase + INT_RESET, trapcritvec); +// sethvec(vectorbase + INT_MCHECK, trapcritvec); + sethvec(vectorbase + INT_DSI, trapvec); + sethvec(vectorbase + INT_ISI, trapvec); + sethvec(vectorbase + INT_EI, trapvec); /* external non-critical intrs */ + sethvec(vectorbase + INT_ALIGN, trapvec); + sethvec(vectorbase + INT_PROG, trapvec); + sethvec(vectorbase + INT_FPU, trapvec); + sethvec(vectorbase + INT_SYSCALL, trapvec); + sethvec(vectorbase + INT_APU, trapvec); + sethvec(vectorbase + INT_PIT, trapvec); + sethvec(vectorbase + INT_FIT, trapvec); +// sethvec(vectorbase + INT_WDT, trapcritvec); +// sethvec2(vectorbase + INT_DMISS, dtlbmiss); +// sethvec2(vectorbase + INT_IMISS, itlbmiss); +// sethvec(vectorbase + INT_DEBUG, trapcritvec); + syncall(); + + /* l.s already set EVPR */ + putmsr(getmsr() | MSR_CE | MSR_ME); /* no MSR_EE here */ + coherence(); +} + +void +trapdisable(void) +{ + putmsr(getmsr() & ~( MSR_EE | MSR_CE | MSR_ME)); /* MSR_DE as well? */ +} + +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; +} + +void +dumpstack(void) +{ + /* sorry. stack is in dram, not Mach now */ +} + +void +dumpregs(Ureg *ureg) +{ + int i; + uintptr *l; + + iprint("cpu%d: registers for boot\n", m->machno); + + 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 +faultpower(Ureg *ureg, ulong addr, int read) +{ + USED(read); + dumpregs(ureg); + panic("boot fault: 0x%lux", addr); +} + +void +trap(Ureg *ur) +{ + int ecode; + u32int esr; + + ur->cause &= 0xFFE0; + ecode = ur->cause; + if(ecode < 0 || ecode >= 0x2000) + ecode = 0x3000; + esr = getesr(); + putesr(0); + + switch(ecode){ + case INT_SYSCALL: + panic("syscall in boot: srr1 %#4.4luX pc %#p\n", + ur->srr1, ur->pc); + + case INT_PIT: + clockintr(ur); + break; + + case INT_MCHECK: + if (probing) { + trapped++; + longjmp(probenv, 1); + } + if(esr & ESR_MCI){ + //iprint("mcheck-mci %lux\n", ur->pc); + faultpower(ur, ur->pc, 1); + break; + } + //iprint("mcheck %#lux esr=%#ux dear=%#ux\n", ur->pc, esr, 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_EI: + intr(ur); + break; + + case INT_PROG: + default: + print("boot %s pc=%#lux\n", excname(ecode, esr), ur->pc); + dumpregs(ur); + dumpstack(); + if(m->machno == 0) + spllo(); + exit(1); + } + splhi(); +} + +static Lock fltlck; + +vlong +probeaddr(uintptr addr) +{ + vlong v; + + ilock(&fltlck); + probing = 1; + /* + * using setjmp & longjmp is a sleazy hack; see ../../9k/vt4/trap.c + * for a less sleazy hack. + */ + if (setjmp(probenv) == 0) + v = *(ulong *)addr; /* this may cause a fault */ + else + v = -1; + probing = 0; + iunlock(&fltlck); + return v; +} + +vlong +qtmprobeaddr(uintptr addr) +{ + int i; + vlong v, junk; + vlong *ptr; + + ilock(&fltlck); + probing = 1; + trapped = 0; + v = 0; + /* + * using setjmp & longjmp is a sleazy hack; see ../../9k/vt4/trap.c + * for a less sleazy hack. + */ + if (setjmp(probenv) == 0) { + syncall(); + clrmchk(); + syncall(); + + ptr = (vlong *)addr; + for (i = 0; !trapped && !(getesr() & ESR_MCI) && + i < DCACHELINESZ/sizeof *ptr; i++) { + ptr[i] = 0; + coherence(); + } + junk = ptr[0]; + USED(junk); + } else + v = -1; + + syncall(); + if(getesr() & ESR_MCI) + v = -1; + syncall(); + clrmchk(); + syncall(); + probing = 0; + iunlock(&fltlck); + return v; +} diff -Nru /sys/src/boot/vt4/uart.c /sys/src/boot/vt4/uart.c --- /sys/src/boot/vt4/uart.c Thu Jan 1 00:00:00 1970 +++ /sys/src/boot/vt4/uart.c Fri Jun 7 00:00:00 2013 @@ -0,0 +1,64 @@ +/* xilinx uartlite driver (polling) */ +#include "include.h" + +enum { + /* UART Lite register offsets */ + Rxfifo = 0, /* receive FIFO, read only */ + Txfifo = 4, /* transmit FIFO, write only */ + Status = 8, /* status register, read only */ + Ctl = 12, /* control reg, write only */ + + /* control register bit positions */ + Ctlintrena = 0x10, /* enable interrupt */ + Rxfiforst = 0x02, /* reset receive FIFO */ + Txfiforst = 0x01, /* reset transmit FIFO */ + + /* status register bit positions */ + Parerr = 0x80, + Framerr = 0x40, + Overrunerr = 0x20, + Stsintrena = 0x10, /* interrupt enabled */ + Txfifofull = 0x08, /* transmit FIFO full */ + Txfifoempty = 0x04, /* transmit FIFO empty */ + Rxfifofull = 0x02, /* receive FIFO full */ + Rxfifohasdata = 0x01, /* data in receive FIFO */ + + FIFO_SIZE = 16, /* bytes in tx or rx fifo */ +}; + +#define Uartctl ((ulong *)(Uartlite + Ctl)) +#define Uartstatus ((ulong *)(Uartlite + Status)) +#define Uartrxfifo ((ulong *)(Uartlite + Rxfifo)) +/* #define Uarttxfifo ((ulong *)(Uartlite + Txfifo)) /* see prototype.h */ + +void +vuartputc(int c) +{ + int i; + + coherence(); + i = 2000000; /* allow > 1.04 ms per char @ 9600 baud */ + while(*Uartstatus & Txfifofull && i-- > 0) + ; + *Uarttxfifo = (uchar)c; + coherence(); +} + +int +vuartputs(char *s, int len) +{ + while (len-- > 0) { + if (*s == '\n') + vuartputc('\r'); + vuartputc(*s++); + } + return len; +} + +int +vuartgetc(void) +{ + while((*Uartstatus & Rxfifohasdata) == 0) + ; + return (uchar)*Uartrxfifo; +} diff -Nru /sys/src/boot/vt4/virtex4 /sys/src/boot/vt4/virtex4 --- /sys/src/boot/vt4/virtex4 Thu Jan 1 00:00:00 1970 +++ /sys/src/boot/vt4/virtex4 Fri Jun 7 00:00:00 2013 @@ -0,0 +1,26 @@ +# rae's virtex4 ml410 boot +power + l + load + trap + clock + archvt4 + intr + uart + ethertemac + llfifo + fakeqtm +# port stuff + portclock + malloc + print + console + taslock + ether + boot + fs + bootp + +lib + libip + libc diff -Nru /sys/src/boot/vt4/words /sys/src/boot/vt4/words --- /sys/src/boot/vt4/words Thu Jan 1 00:00:00 1970 +++ /sys/src/boot/vt4/words Fri Jun 7 00:00:00 2013 @@ -0,0 +1,18 @@ +This bootstrap is intended to load a Plan 9 kernel via bootp and tftp +into a Xilinx Virtex 4 ML410 board. It shares code with the ML510 +boot in ../vt5. The mkfile generates an elf file which is then fed +into the Xilinx CAD tool to generate a bitstream for loading into the +FPGA on the ML410. + +This bootstrap will almost certainly not work for you without some +changes. In particular, the addresses of the I/O registers in +physmem.h will have to be changed to match yours and you'll need to +make sure that they are mapped if you have more than 512K of them. + +This bootstrap does not use dma but in principle it could, by +replacing calls to fifocpy with calls to dmacpy. dma is one more +thing that could go wrong, so we ended up using the cpu to copy words +to and from ethernet fifos. + +This code runs in high memory (above 0xfffe0000) and its global data +is thus in sram. On the Virtex 4, the bootstrap runs with the MMU off.