diff options
Diffstat (limited to 'os/boot/rpcg')
54 files changed, 11523 insertions, 0 deletions
diff --git a/os/boot/rpcg/NOTICE b/os/boot/rpcg/NOTICE new file mode 100644 index 00000000..b0086fa7 --- /dev/null +++ b/os/boot/rpcg/NOTICE @@ -0,0 +1,3 @@ +Inferno® Copyright © 1996-1999 Lucent Technologies Inc. All rights reserved. +PowerPC support Copyright © 1995-1997 C H Forsyth (forsyth@caldo.demon.co.uk). All rights reserved. +MPC8xx Inferno PowerPC port Copyright © 1998-2003 Vita Nuova Holdings Limited. All rights reserved. diff --git a/os/boot/rpcg/alarm.c b/os/boot/rpcg/alarm.c new file mode 100644 index 00000000..2aa4431a --- /dev/null +++ b/os/boot/rpcg/alarm.c @@ -0,0 +1,123 @@ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" +#define MAXALARM 10 + +Alarm alarmtab[MAXALARM]; + +/* + * Insert new into list after where + */ +void +insert(List **head, List *where, List *new) +{ + if(where == 0){ + new->next = *head; + *head = new; + }else{ + new->next = where->next; + where->next = new; + } + +} + +/* + * Delete old from list. where->next is known to be old. + */ +void +delete(List **head, List *where, List *old) +{ + if(where == 0){ + *head = old->next; + return; + } + where->next = old->next; +} + +Alarm* +newalarm(void) +{ + int i; + Alarm *a; + + for(i=0,a=alarmtab; i < nelem(alarmtab); i++,a++) + if(a->busy==0 && a->f==0){ + a->f = 0; + a->arg = 0; + a->busy = 1; + return a; + } + panic("newalarm"); + return 0; /* not reached */ +} + +Alarm* +alarm(int ms, void (*f)(Alarm*), void *arg) +{ + Alarm *a, *w, *pw; + ulong s; + + if(ms < 0) + ms = 0; + s = splhi(); + a = newalarm(); + a->dt = MS2TK(ms); + a->f = f; + a->arg = arg; + pw = 0; + for(w=m->alarm; w; pw=w, w=w->next){ + if(w->dt <= a->dt){ + a->dt -= w->dt; + continue; + } + w->dt -= a->dt; + break; + } + insert(&m->alarm, pw, a); + splx(s); + return a; +} + +void +cancel(Alarm *a) +{ + a->f = 0; +} + +void +alarminit(void) +{ +} + +#define NA 10 /* alarms per clock tick */ +void +checkalarms(void) +{ + int i, n, s; + Alarm *a; + void (*f)(Alarm*); + Alarm *alist[NA]; + + s = splhi(); + a = m->alarm; + if(a){ + for(n=0; a && a->dt<=0 && n<NA; n++){ + alist[n] = a; + delete(&m->alarm, 0, a); + a = m->alarm; + } + if(a) + a->dt--; + + for(i = 0; i < n; i++){ + f = alist[i]->f; /* avoid race with cancel */ + if(f) + (*f)(alist[i]); + alist[i]->busy = 0; + } + } + splx(s); +} diff --git a/os/boot/rpcg/all.h b/os/boot/rpcg/all.h new file mode 100644 index 00000000..0612bf04 --- /dev/null +++ b/os/boot/rpcg/all.h @@ -0,0 +1,6 @@ +#include "u.h" +#include "lib.h" +#include "dat.h" +#include "fns.h" +#include "mem.h" +#include "io.h" diff --git a/os/boot/rpcg/archrpcg.c b/os/boot/rpcg/archrpcg.c new file mode 100644 index 00000000..87df2196 --- /dev/null +++ b/os/boot/rpcg/archrpcg.c @@ -0,0 +1,279 @@ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" + +#include "archrpcg.h" +#include "etherif.h" + +/* + * board-specific support for the RPCG RXLite + */ + +enum { + SYSMHZ = 66, /* target frequency */ + + /* sccr */ + RTSEL = IBIT(8), /* =0, select main oscillator (OSCM); =1, select external crystal (EXTCLK) */ + RTDIV = IBIT(7), /* =0, divide by 4; =1, divide by 512 */ + CRQEN = IBIT(9), /* =1, switch to high frequency when CPM active */ + PRQEN = IBIT(10), /* =1, switch to high frequency when interrupt pending */ + + /* plprcr */ + CSRC = IBIT(21), /* =0, clock is DFNH; =1, clock is DFNL */ +}; + +static char flashsig[] = "RPXsignature=1.0\nNAME=qbrpcg\nSTART=FFC20100\nVERSION=1.1\n"; +static char* geteeprom(char*); + +/* + * called early in main.c, after machinit: + * using board and architecture specific registers, initialise + * 8xx registers that need it and complete initialisation of the Mach structure. + */ +void +archinit(void) +{ + IMM *io; + int mf, t; + ulong v; + + v = getimmr() & 0xFFFF; + switch(v>>8){ + case 0x00: t = 0x86000; break; + case 0x20: t = 0x82300; break; + case 0x21: t = 0x823a0; break; + default: t = 0; break; + } + m->cputype = t; + m->bcsr = KADDR(BCSRMEM); + io = m->iomem; + m->clockgen = 8*MHz; + mf = (io->plprcr >> 20)+1; /* use timing set by bootstrap */ + m->cpuhz = m->clockgen*mf; + m->bcsr[0] = DisableColTest | DisableFullDplx | DisableUSB | HighSpdUSB | LedOff; /* first write enables bcsr regs */ +return; + io->plprcrk = KEEP_ALIVE_KEY; + io->plprcr &= ~CSRC; /* general system clock is DFNH */ +/* io->mptpr = 0x0800; /* memory prescaler = 8 for refresh */ + /* use memory refresh time set by RPXLite monitor */ + io->plprcrk = ~KEEP_ALIVE_KEY; +} + +void +cpuidprint(void) +{ + int t, v; + + print("Inferno bootstrap\n"); + print("PVR: "); + t = getpvr()>>16; + switch(t){ + case 0x01: print("MPC601"); break; + case 0x03: print("MPC603"); break; + case 0x04: print("MPC604"); break; + case 0x06: print("MPC603e"); break; + case 0x07: print("MPC603e-v7"); break; + case 0x50: print("MPC8xx"); break; + default: print("PowerPC version #%x", t); break; + } + print(", revision #%lux\n", getpvr()&0xffff); + print("IMMR: "); + v = getimmr() & 0xFFFF; + switch(v>>8){ + case 0x00: print("MPC860/821"); break; + case 0x20: print("MPC823"); break; + case 0x21: print("MPC823A"); break; + default: print("Type #%lux", v>>8); break; + } + print(", mask #%lux\n", v&0xFF); + print("options: #%lux\n", archoptionsw()); + print("bcsr: %8.8lux\n", m->bcsr[0]); + print("PLPRCR=%8.8lux SCCR=%8.8lux\n", m->iomem->plprcr, m->iomem->sccr); + print("%lud MHz system\n", m->cpuhz/MHz); + print("\n"); +//print("%s\n", geteeprom("EA")); +print("BR0=%8.8lux OR0=%8.8lux\n", m->iomem->memc[0].base, m->iomem->memc[0].option); +print("MPTPR=%8.8lux\n", m->iomem->mptpr); +} + +static char* defplan9ini[2] = { + /* 860/821 */ + "ether0=type=SCC port=1 ea=0010ec000051\r\n" + "vgasize=640x480x8\r\n" + "kernelpercent=40\r\n" + "console=0\r\nbaud=9600\r\n", + + /* 823 */ + "ether0=type=SCC port=2 ea=0010ec000051\r\n" + "vgasize=640x480x8\r\n" + "kernelpercent=40\r\n" + "console=0\r\nbaud=9600\r\n", +}; + +char * +archconfig(void) +{ + print("Using default configuration\n"); + return defplan9ini[MPCMODEL(m->cputype) == 0x823]; +} + +/* + * provide value for #r/switch (devrtc.c) + */ +int +archoptionsw(void) +{ + return (m->bcsr[0]&DipSwitchMask)>>4; +} + +/* + * invoked by clock.c:/^clockintr + */ +static void +twinkle(void) +{ + if(m->ticks%MS2TK(1000) == 0) + m->bcsr[0] ^= LedOff; +} + +void (*archclocktick)(void) = twinkle; + +/* + * for flash.c:/^flashreset + * retrieve flash type, virtual base and length and return 0; + * return -1 on error (no flash) + */ +int +archflashreset(char *type, void **addr, long *length) +{ + if((m->iomem->memc[BOOTCS].base & 1) == 0) + return -1; /* shouldn't happen */ + strcpy(type, "AMD29F0x0"); + *addr = KADDR(FLASHMEM); + *length = 4*1024*1024; + return 0; +} + +int +archether(int ctlrno, Card *ether) +{ + char *ea; + + if(ctlrno > 0) + return -1; + strcpy(ether->type, "SCC"); + ether->port = 2; + ea = geteeprom("EA"); + if(ea != nil) + parseether(ether->ea, ea); + return 1; +} + +/* + * enable the clocks for the given SCC ether and reveal them to the caller. + * do anything else required to prepare the transceiver (eg, set full-duplex, reset loopback). + */ +int +archetherenable(int cpmid, int *rcs, int *tcs) +{ + IMM *io; + + switch(cpmid){ + default: + /* no other SCCs are wired for ether on RPXLite*/ + return -1; + + case SCC2ID: + io = ioplock(); + m->bcsr[0] |= EnableEnet; + io->papar |= SIBIT(6)|SIBIT(4); /* enable CLK2 and CLK4 */ + io->padir &= ~(SIBIT(6)|SIBIT(4)); + *rcs = CLK4; + *tcs = CLK2; + iopunlock(); + break; + } + return 0; +} + +void +archetherdisable(int id) +{ + USED(id); + m->bcsr[0] &= ~EnableEnet; +} + +/* + * do anything extra required to enable the UART on the given CPM port + */ +void +archenableuart(int id, int irda) +{ + USED(id, irda); +} + +/* + * do anything extra required to disable the UART on the given CPM port + */ +void +archdisableuart(int id) +{ + USED(id); +} + +/* + * enable/disable the LCD panel's backlight + */ +void +archbacklight(int on) +{ + USED(on); +} + +static char* +geteeprom(char *s) +{ + static int init; + static char res[64]; + static uchar eeprom[257]; + uchar *l, *p; + int i, j; + + if(!init){ + i2csetup(); + if(i2crecv(0xa8|1|(0<<8), eeprom, 128) < 0 || + i2crecv(0xa8|1|(128<<8), eeprom+128, 128) < 0){ + print("i2c failed\n"); + return nil; + } + if(0){ + print("eeprom:\n"); + for(i=0; i<16; i++){for(j=0; j<16; j++)print(" %2.2ux[%c]", eeprom[i*16+j], eeprom[i*16+j]); print("\n");} + } + eeprom[256] = 0xFF; + init = 1; + } + for(l = eeprom; *l != 0xFF && *l != '\n';){ + p = l; + while(*l != '\n' && *l != 0xFF && *l != '=') + l++; + if(*l == '='){ + if(l-p == strlen(s) && strncmp(s, (char*)p, strlen(s)) == 0){ + p = l+1; + while(*l != '\n' && *l != 0xFF) + l++; + memmove(res, p, l-p); + res[l-p] = 0; + return res; + } + } + while(*l != '\n' && *l != 0xFF) + l++; + if(*l == '\n') + l++; + } + return nil; +} diff --git a/os/boot/rpcg/archrpcg.h b/os/boot/rpcg/archrpcg.h new file mode 100644 index 00000000..2ea4e39b --- /dev/null +++ b/os/boot/rpcg/archrpcg.h @@ -0,0 +1,48 @@ +/* + * values for RPXLite AW + */ +enum { + /* CS assignment */ + BOOTCS = 0, + DRAM1 = 1, + /* CS2 is routed to expansion header */ + BCSRCS = 3, + NVRAMCS = 4, + /* CS5 is routed to expansion header */ + PCMCIA0CS = 6, /* select even bytes */ + PCMCIA1CS = 7, /* select odd bytes */ +}; + +/* + * BCSR bits (there are 4 8-bit registers that we access as ulong) + */ +enum { + EnableEnet = IBIT(0), + EnableXcrLB= IBIT(1), + DisableColTest= IBIT(2), + DisableFullDplx=IBIT(3), + LedOff= IBIT(4), + DisableUSB= IBIT(5), + HighSpdUSB= IBIT(6), + EnableUSBPwr= IBIT(7), + /* 8,9,10 unused */ + PCCVCCMask= IBIT(12)|IBIT(13), + PCCVPPMask= IBIT(14)|IBIT(15), + PCCVCC0V= 0, + PCCVCC5V= IBIT(13), + PCCVCC3V= IBIT(12), + PCCVPP0V= 0, + PCCVPP5V= IBIT(14), + PCCVPP12V= IBIT(15), + PCCVPPHiZ= IBIT(14)|IBIT(15), + /* 16-23 NYI */ + DipSwitchMask= IBIT(24)|IBIT(25)|IBIT(26)|IBIT(27), + DipSwitch0= IBIT(24), + DipSwitch1= IBIT(25), + DipSwitch2= IBIT(26), + DipSwitch3= IBIT(27), + /* bit 28 RESERVED */ + FlashComplete= IBIT(29), + NVRAMBattGood= IBIT(30), + RTCBattGood= IBIT(31), +}; diff --git a/os/boot/rpcg/boot.h b/os/boot/rpcg/boot.h new file mode 100644 index 00000000..1b2a09fb --- /dev/null +++ b/os/boot/rpcg/boot.h @@ -0,0 +1,8 @@ +#include <u.h> +#include "lib.h" + +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" +#include "ureg.h" diff --git a/os/boot/rpcg/bootp.c b/os/boot/rpcg/bootp.c new file mode 100644 index 00000000..13e7ba1a --- /dev/null +++ b/os/boot/rpcg/bootp.c @@ -0,0 +1,509 @@ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" + +#include "ip.h" + +#define XPADDR(a) ((ulong)(a) & ~KSEGM) + +enum { + CHECKSUM = 1, /* set zero if trouble booting from Linux */ +}; + +uchar broadcast[Eaddrlen] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +}; + +static ushort tftpport = 5000; +static int Id = 1; +static Netaddr myaddr; +static Netaddr server; + +typedef struct { + uchar header[4]; + uchar data[Segsize]; +} Tftp; +static Tftp tftpb; + +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; + static 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 = sizeof(Udphdr)+dlen; + 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)); + + 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; + strcpy(buf+4, msg); + n = strlen(msg) + 4 + 1; + udpsend(ctlrno, a, buf, n); + if(report) + print("\ntftp: error(%d): %s\n", code, msg); +} + +static int +udprecv(int ctlrno, Netaddr *a, void *data, int dlen) +{ + int n, len; + ushort csm; + Udphdr *h; + ulong addr, timo; + static 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(nhgets(h->type) != ET_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) + continue; + + h->ttl = 0; + len = nhgets(h->udplen); + hnputs(h->udpplen, len); + + if(CHECKSUM && nhgets(h->udpcksum)) { + csm = ptcl_csum(&h->ttl, len+UDP_PHDRSIZE); + if(csm != 0) { + print("udp chksum error csum #%4lux len %d\n", csm, n); + break; + } + } + + if(a->port != 0 && nhgets(h->udpsport) != a->port) + continue; + + addr = nhgetl(h->udpsrc); + if(a->ip != Bcastip && addr != a->ip) + continue; + + len -= UDP_HDRSIZE-UDP_PHDRSIZE; + if(len > dlen) { + print("udp: packet too big\n"); + 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; + +static int +tftpopen(int ctlrno, Netaddr *a, char *name, Tftp *tftp) +{ + int i, len, rlen, oport; + char buf[Segsize+2]; + + buf[0] = 0; + buf[1] = Tftp_READ; + len = sprint(buf+2, "%s", name) + 2; + len += sprint(buf+len+1, "octet") + 2; + + 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], tftp->data); + return -1; + + case Tftp_DATA: + 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; + } + return rlen-sizeof(tftp->header); + } + } + + print("tftpopen: failed to connect to server\n"); + return -1; +} + +static int +tftpread(int ctlrno, Netaddr *a, Tftp *tftp, int dlen) +{ + int blockno, len, retry; + uchar buf[4]; + + buf[0] = 0; + buf[1] = Tftp_ACK; + buf[2] = tftpblockno>>8; + buf[3] = tftpblockno; + tftpblockno++; + + dlen += sizeof(tftp->header); + + retry = 0; +buggery: + udpsend(ctlrno, a, buf, sizeof(buf)); + + if((len = udprecv(ctlrno, a, tftp, dlen)) < dlen){ + print("tftpread: %d != %d\n", len, dlen); + nak(ctlrno, a, 2, "short read", 0); + if(retry++ < 5) + goto buggery; + return -1; + } + + blockno = (tftp->header[2]<<8)|tftp->header[3]; + if(blockno != tftpblockno){ + print("?"); + + if(blockno == tftpblockno-1 && retry++ < 8) + goto buggery; + print("tftpread: block error: %d, expected %d\n", blockno, tftpblockno); + nak(ctlrno, a, 1, "block error", 0); + + return -1; + } + + return len-sizeof(tftp->header); +} + +int +bootp(int ctlrno, char *file) +{ + Bootp req, rep; + int i, dlen, segsize, text, data, bss, total; + uchar *ea, *addr, *p; + ulong entry; + Exec *exec; + char name[128], *filename, *sysname; + + if((ea = etheraddr(ctlrno)) == 0){ + print("invalid ctlrno %d\n", ctlrno); + return -1; + } + + filename = 0; + sysname = 0; + if(file && *file){ + strcpy(name, file); + if(filename = strchr(name, ':')){ + if(filename != name && *(filename-1) != '\\'){ + 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); + + myaddr.ip = 0; + myaddr.port = BPportsrc; + memmove(myaddr.ea, ea, Eaddrlen); + + 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 timed out\n"); + return -1; + } + + if(filename == 0 || *filename == 0) + 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);uartwait(); + + myaddr.ip = nhgetl(rep.yiaddr); + myaddr.port = tftpport++; + server.ip = nhgetl(rep.siaddr); + server.port = TFTPport; + + if((dlen = tftpopen(ctlrno, &server, filename, &tftpb)) < 0) + return -1; + exec = (Exec*)(tftpb.data); + if(dlen < sizeof(Exec) || GLLONG(exec->magic) != Q_MAGIC){ + nak(ctlrno, &server, 0, "bad magic number", 1); + return -1; + } + text = GLLONG(exec->text); + data = GLLONG(exec->data); + bss = GLLONG(exec->bss); + total = text+data+bss; + entry = GLLONG(exec->entry); +print("load@%8.8lux: ", XPADDR(entry));uartwait(); + print("%d", text); + + addr = (uchar*)XPADDR(entry); + p = tftpb.data+sizeof(Exec); + dlen -= sizeof(Exec); + segsize = text; + for(;;){ + if(dlen == 0){ + if((dlen = tftpread(ctlrno, &server, &tftpb, sizeof(tftpb.data))) < 0) + return -1; + p = tftpb.data; + } + if(segsize <= dlen) + i = segsize; + else + i = dlen; + memmove(addr, p, i); + + addr += i; + p += i; + segsize -= i; + dlen -= i; + + if(segsize <= 0){ + if(data == 0) + break; + print("+%d", data); + segsize = data; + data = 0; + addr = (uchar*)PGROUND((ulong)addr); + } + } + nak(ctlrno, &server, 3, "ok", 0); /* tftpclose */ + print("+%d=%d\n", bss, total); + print("entry: 0x%lux\n", entry); + uartwait(); + scc2stop(); + splhi(); + (*(void(*)(void))(XPADDR(entry)))(); + + return 0; +} diff --git a/os/boot/rpcg/clock.c b/os/boot/rpcg/clock.c new file mode 100644 index 00000000..4d2d6bfd --- /dev/null +++ b/os/boot/rpcg/clock.c @@ -0,0 +1,71 @@ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" +#include "ureg.h" + +enum { + Timebase = 4, /* system clock cycles per time base cycle */ +}; + +void (*archclocktick)(void); /* set by arch*.c when desired */ + +static ulong clkreload; + +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++) + ; +} + +void +clockintr(Ureg*, void*) +{ + putdec(clkreload); + m->ticks++; + checkalarms(); + if(archclocktick != nil) + archclocktick(); +} + +void +clockinit(void) +{ + long x; + + m->delayloop = m->cpuhz/1000; /* initial estimate */ + do { + x = gettbl(); + delay(10); + x = gettbl() - x; + } while(x < 0); + + /* + * fix count + */ + m->delayloop = ((vlong)m->delayloop*(10*m->clockgen/1000))/(x*Timebase); + if(m->delayloop == 0) + m->delayloop = 1; + clkreload = (m->clockgen/Timebase)/HZ-1; + putdec(clkreload); +} diff --git a/os/boot/rpcg/conf.c b/os/boot/rpcg/conf.c new file mode 100644 index 00000000..4ecb4b3e --- /dev/null +++ b/os/boot/rpcg/conf.c @@ -0,0 +1,173 @@ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" + +#include "dosfs.h" + +static char *confname[MAXCONF]; +static char *confval[MAXCONF]; +static int nconf; + +extern char **ini; + +char* +getconf(char *name) +{ + int i; + + for(i = 0; i < nconf; i++) + if(strcmp(confname[i], name) == 0) + return confval[i]; + return 0; +} + +/* + * read configuration file + */ +int +plan9ini(Dos *dos, char *val) +{ + Dosfile rc; + int i, n; + char *cp, *p, *q, *line[MAXCONF]; + + cp = BOOTARGS; + if(dos) { + if(dosstat(dos, *ini, &rc) <= 0) + return -1; + + *cp = 0; + n = dosread(&rc, cp, BOOTARGSLEN-1); + if(n <= 0) + return -1; + cp[n] = 0; + } else if(val != nil){ + if(memchr(val, 0, BOOTARGSLEN-1) == nil) + return -1; + print("Using flash configuration\n"); + strcpy(cp, val); + n = strlen(cp); + }else{ + strcpy(cp, archconfig()); + n = strlen(cp); + } + + /* + * Make a working 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. + */ + memmove(cp+BOOTARGSLEN, cp, n+1); + cp += BOOTARGSLEN; + + /* + * Strip out '\r', change '\t' -> ' '. + */ + p = cp; + for(q = cp; *q; q++){ + if(*q == '\r') + continue; + if(*q == '\t') + *q = ' '; + *p++ = *q; + } + *p = 0; + n = getcfields(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; +} + +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; + + sprint(cc, "%s%d", class, ctlrno); + for(n = 0; n < nconf; n++){ + if(strncmp(confname[n], cc, NAMELEN)) + continue; + isa->nopt = 0; + p = confval[n]; + while(*p){ + while(*p == ' ' || *p == '\t') + p++; + if(*p == '\0') + break; + if(strncmp(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(strncmp(p, "port=", 5) == 0) + isa->port = strtoul(p+5, &p, 0); + else if(strncmp(p, "irq=", 4) == 0) + isa->irq = strtoul(p+4, &p, 0); + else if(strncmp(p, "mem=", 4) == 0) + isa->mem = strtoul(p+4, &p, 0); + else if(strncmp(p, "size=", 5) == 0) + isa->size = strtoul(p+5, &p, 0); + else if(strncmp(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 --git a/os/boot/rpcg/console.c b/os/boot/rpcg/console.c new file mode 100644 index 00000000..9a05c122 --- /dev/null +++ b/os/boot/rpcg/console.c @@ -0,0 +1,173 @@ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" + +static Queue* consiq; +static Queue* consoq; + +void +bothputs(char *s, int n) +{ + uartputs(s, n); + screenputs(s, n); +} + +static void (*consputs)(char*, int) = bothputs; /* or screenputs */ + +void +consinit(void) +{ + char *p; + int baud, port; + static int cgadone; + + p = getconf("console"); + if(0) + if(p == 0 || strcmp(p, "lcd") == 0 || strcmp(p, "screen") == 0){ + consiq = qopen(4*1024, 0, 0, 0); + consoq = qopen(8*1024, 0, 0, 0); + consputs = screenputs; + return; + } + if(p!=0 && strstr(p, "lcd") == 0) + consputs = bothputs; + else + consputs = uartputs; +//consputs = screenputs; + port = 0; + if(p) + port = strtoul(p, 0, 0); + baud = 0; + if(p = getconf("baud")) + baud = strtoul(p, 0, 0); + if(baud == 0) + baud = 9600; + uartspecial(port, baud, &consiq, &consoq, kbdchar); +} + +void +kbdchar(Queue *q, int c) +{ + c &= 0x7F; + if(c == 0x10) + panic("^p"); + qbputc(q, c); +} + +static int +getline(char *buf, int size, int dotimeout) +{ + int c, i=0; + ulong start; + char echo; + + for (;;) { + start = m->ticks; + do{ + if(dotimeout && ((m->ticks - start) > 5*HZ)) + return -2; + c = qbgetc(consiq); + }while(c == -1); + 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 len, isdefault; + + buf[0] = 0; + isdefault = (def && *def); + for (;;) { + if(isdefault) + print("%s[default==%s]: ", prompt, def); + else + print("%s: ", prompt); + len = getline(buf, size, isdefault); + switch(len){ + 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) + strcpy(buf, def); + return 0; +} + +int +sprint(char *s, char *fmt, ...) +{ + return donprint(s, s+PRINTSIZE, fmt, (&fmt+1)) - s; +} + +int +print(char *fmt, ...) +{ + char buf[PRINTSIZE]; + int n; + + if(consputs == 0) + return 0; + n = donprint(buf, buf+sizeof(buf), fmt, (&fmt+1)) - buf; + (*consputs)(buf, n); + return n; +} + +void +panic(char *fmt, ...) +{ + char buf[PRINTSIZE]; + int n; + + if(consputs){ + (*consputs)("panic: ", 7); + n = donprint(buf, buf+sizeof(buf), fmt, (&fmt+1)) - buf; + (*consputs)(buf, n); + (*consputs)("\n", 1); + } + spllo(); + for(;;) + idle(); +} diff --git a/os/boot/rpcg/cpm.c b/os/boot/rpcg/cpm.c new file mode 100644 index 00000000..a9a45d60 --- /dev/null +++ b/os/boot/rpcg/cpm.c @@ -0,0 +1,162 @@ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" + +enum { + BDSIZE= 1024, /* TO DO: check this */ +}; + +static Map bdmapv[BDSIZE/sizeof(BD)]; +static RMap bdmap = {"buffer descriptors"}; + +void +cpminit(void) +{ + IMM *io; + + io = m->iomem; + io->sdcr = 1; + io->lccr &= ~1; /* disable LCD */ + io->pcint = 0; /* disable all port C interrupts */ + io->pcso = 0; + io->pcdir =0; + io->pcpar = 0; + io->pcdat = 0; + io->papar = 0; + io->padir = 0; + io->paodr = 0; + io->padat = 0; + io->pbpar = 0; + io->pbdir = 0; + io->pbodr = 0; + io->pbdat = 0; + eieio(); + + for(io->cpcr = 0x8001; io->cpcr & 1;) /* reset all CPM channels */ + eieio(); + + mapinit(&bdmap, bdmapv, sizeof(bdmapv)); + mapfree(&bdmap, DPBASE, BDSIZE); +} + +void +cpmop(int op, int cno, int param) +{ + IMM *io; + int s; + + s = splhi(); + io = m->iomem; + eieio(); + while(io->cpcr & 1) + eieio(); + io->cpcr = (op<<8)|(cno<<4)|(param<<1)|1; + eieio(); + while(io->cpcr & 1) + eieio(); + splx(s); +} + +/* + * connect SCCx clocks in NSMI mode (x=1 for USB) + */ +void +sccnmsi(int x, int rcs, int tcs) +{ + IMM *io; + ulong v; + int sh; + + sh = (x-1)*8; /* each SCCx field in sicr is 8 bits */ + v = (((rcs&7)<<3) | (tcs&7)) << sh; + io = ioplock(); + io->sicr = (io->sicr & ~(0xFF<<sh)) | v; + iopunlock(); +} + +void +scc2stop(void) +{ + SCC *scc; + + scc = IOREGS(0xA20, SCC); + if(scc->gsmrl & (3<<4)){ + cpmop(GracefulStopTx, SCC2ID, 0); + cpmop(CloseRxBD, SCC2ID, 0); + delay(1); + scc->gsmrl &= ~(3<<4); /* disable current use */ + archetherdisable(SCC2ID); + } +} + +BD * +bdalloc(int n) +{ + ulong a; + + a = mapalloc(&bdmap, 0, n*sizeof(BD), 0); + if(a == 0) + panic("bdalloc"); + return KADDR(a); +} + +void +bdfree(BD *b, int n) +{ + if(b){ + eieio(); + mapfree(&bdmap, PADDR(b), n*sizeof(BD)); + } +} + +/* + * initialise receive and transmit buffer rings. + */ +int +ioringinit(Ring* r, int nrdre, int ntdre, int bufsize) +{ + int i, x; + + /* the ring entries must be aligned on sizeof(BD) boundaries */ + r->nrdre = nrdre; + if(r->rdr == nil) + r->rdr = bdalloc(nrdre); + /* the buffer size must align with cache lines since the cache doesn't snoop */ + bufsize = (bufsize+CACHELINESZ-1)&~(CACHELINESZ-1); + if(r->rrb == nil) + r->rrb = malloc(nrdre*bufsize); + if(r->rdr == nil || r->rrb == nil) + return -1; + dcflush(r->rrb, nrdre*bufsize); + x = PADDR(r->rrb); + for(i = 0; i < nrdre; i++){ + r->rdr[i].length = 0; + r->rdr[i].addr = x; + r->rdr[i].status = BDEmpty|BDInt; + x += bufsize; + } + r->rdr[i-1].status |= BDWrap; + r->rdrx = 0; + + r->ntdre = ntdre; + if(r->tdr == nil) + r->tdr = bdalloc(ntdre); + if(r->txb == nil) + r->txb = malloc(ntdre*sizeof(Block*)); + if(r->tdr == nil || r->txb == nil) + return -1; + for(i = 0; i < ntdre; i++){ + r->txb[i] = nil; + r->tdr[i].addr = 0; + r->tdr[i].length = 0; + r->tdr[i].status = 0; + } + r->tdr[i-1].status |= BDWrap; + r->tdrh = 0; + r->tdri = 0; + r->ntq = 0; + return 0; +} diff --git a/os/boot/rpcg/crc32.c b/os/boot/rpcg/crc32.c new file mode 100644 index 00000000..78bdacba --- /dev/null +++ b/os/boot/rpcg/crc32.c @@ -0,0 +1,42 @@ +#include "boot.h" + +/* + * from Rob Warnock + */ +static ulong crc32tab[256]; /* initialised on first call to crc32 */ + +enum { + CRC32POLY = 0x04c11db7 /* AUTODIN II, Ethernet, & FDDI */ +}; + +/* + * Build auxiliary table for parallel byte-at-a-time CRC-32. + */ +static void +initcrc32(void) +{ + int i, j; + ulong c; + + for(i = 0; i < 256; i++) { + for(c = i << 24, j = 8; j > 0; j--) + if(c & (1<<31)) + c = (c<<1) ^ CRC32POLY; + else + c <<= 1; + crc32tab[i] = c; + } +} + +ulong +crc32(void *buf, int n, ulong crc) +{ + uchar *p; + + if(crc32tab[1] == 0) + initcrc32(); + crc = ~crc; + for(p = buf; --n >= 0;) + crc = (crc << 8) ^ crc32tab[(crc >> 24) ^ *p++]; + return ~crc; +} diff --git a/os/boot/rpcg/dat.h b/os/boot/rpcg/dat.h new file mode 100644 index 00000000..edadc030 --- /dev/null +++ b/os/boot/rpcg/dat.h @@ -0,0 +1,217 @@ +typedef struct Alarm Alarm; +typedef struct Block Block; +typedef struct IMM IMM; +typedef struct Queue Queue; + +typedef struct List { + void *next; +} List; + +typedef struct { + int fake; + int pri; +} Lock; +#define lock(x) +#define unlock(x) + +struct Alarm { + List; + int busy; + long dt; + void (*f)(Alarm*); + void *arg; +}; + +enum { + Eaddrlen = 6, + ETHERMINTU = 60, /* minimum transmit size */ + ETHERMAXTU = 1514, /* maximum transmit size */ + ETHERHDRSIZE = 14, /* size of an ethernet header */ + + MaxEther = 4, +}; + +typedef struct { + uchar d[Eaddrlen]; + uchar s[Eaddrlen]; + uchar type[2]; + uchar data[1500]; + uchar crc[4]; +} Etherpkt; + +extern uchar broadcast[Eaddrlen]; + +enum { + Npart = 20+2, /* 8 sub partitions, disk, and partition */ + Maxxfer = 16*1024, /* maximum transfer size/cmd */ +}; + +typedef struct { + ulong start; + ulong end; + char name[NAMELEN+1]; +} Partition; + +typedef struct { + int online; + int npart; /* number of real partitions */ + Partition p[Npart]; + ulong offset; + Partition *current; /* current partition */ + + ulong cap; /* total bytes */ + int bytes; /* bytes/sector */ + int sectors; /* sectors/track */ + int heads; /* heads/cyl */ + long cyl; /* cylinders/drive */ + + char lba; /* true if drive has logical block addressing */ + char multi; /* non-zero if drive does multiple block xfers */ +} Disc; + +enum { + ScsiTestunit = 0x00, + ScsiExtsens = 0x03, + ScsiInquiry = 0x12, + ScsiModesense = 0x1a, + ScsiStartunit = 0x1B, + ScsiStopunit = 0x1B, + ScsiGetcap = 0x25, + ScsiRead = 0x08, + ScsiWrite = 0x0a, + ScsiExtread = 0x28, + ScsiExtwrite = 0x2a, + + /* data direction */ + ScsiIn = 1, + ScsiOut = 0, +}; + +typedef struct Scsibuf Scsibuf; +typedef struct Scsibuf { + void* virt; + void* phys; + Scsibuf* next; +}; + +typedef struct Scsidata { + uchar* base; + uchar* lim; + uchar* ptr; +} Scsidata; + +typedef struct Ureg Ureg; + +typedef struct Scsi { + ulong pid; + ushort target; + ushort lun; + ushort rflag; + ushort status; + Scsidata cmd; + Scsidata data; + Scsibuf* b; + uchar* save; + uchar cmdblk[16]; +} Scsi; + +typedef struct Segdesc { + ulong d0; + ulong d1; +} Segdesc; + +typedef struct Mach { + ulong ticks; /* of the clock since boot time */ + ulong delayloop; + long cpuhz; /* general system clock (cycles) */ + long clockgen; /* clock generator frequency (cycles) */ + ulong cpupvr; /* cpu type in processor version register */ + ulong cputype; /* cpu variant in BCD (eg, 0x823xx) */ + void* alarm; /* alarms bound to this clock */ + ulong* bcsr; + IMM* iomem; +} Mach; + +/* Mach.cputype */ +#define MPCREV(x) ((x) & 0xFF) +#define MPCMODEL(x) (((x)>>8) & 0xFFF) +#define MPCFAMILY(x) (((x)>>24) & 0x0F) + + +extern Mach *m; + +#define Q_MAGIC ((((4*21)+0)*21)+7) + +typedef struct Exec Exec; +struct Exec +{ + uchar magic[4]; /* magic number */ + uchar text[4]; /* size of text segment */ + uchar data[4]; /* size of initialized data */ + uchar bss[4]; /* size of uninitialized data */ + uchar syms[4]; /* size of symbol table */ + uchar entry[4]; /* entry point */ + uchar spsz[4]; /* size of sp/pc offset table */ + uchar pcsz[4]; /* size of pc/line number table */ +}; + +/* + * bootline passed by boot program + */ +#define BOOTLINE ((char *)0x200000-150) + +/* + * Where we leave configuration info. + */ +#define BOOTARGS ((char*)(0x200000)) +#define BOOTARGSLEN 1024 +#define MAXCONF 32 + +/* + * a parsed plan9.ini line + */ +#define ISAOPTLEN 16 +#define NISAOPT 8 + +typedef struct ISAConf { + char type[NAMELEN]; + ulong port; + ulong irq; + ulong mem; + ulong size; + uchar ea[6]; + + int nopt; + char opt[NISAOPT][ISAOPTLEN]; +} ISAConf; + +typedef struct { + int size; + ulong addr; +} Map; + +typedef struct { + char* name; + Map* map; + Map* mapend; + + Lock; +} RMap; + +typedef struct PCIcfg PCIcfg; + +extern uchar* vgamem; + +struct Block { + uchar *rp; + uchar *wp; + uchar *lim; + uchar *data; + Block* next; + ulong magic; +}; +#define BLEN(b) ((b)->wp-(b)->rp) + +typedef struct QLock { + int dummy; +} QLock; diff --git a/os/boot/rpcg/defont0.c b/os/boot/rpcg/defont0.c new file mode 100644 index 00000000..9a25e1bd --- /dev/null +++ b/os/boot/rpcg/defont0.c @@ -0,0 +1,216 @@ +#include <u.h> +#include <libc.h> +#include <libg.h> +#include <gnot.h> + + + +static ulong bits0[] = { + 0x907070f0, 0xf0f07000, 0xf0888888, 0xf8707070, 0xe0e0e0e0, 0xe09070f0, 0x70f870f0, 0xf870f088, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000000e0, + 0xd0808080, 0x80808800, 0x8888c888, 0x80888888, 0x90909090, 0x90d08080, 0x80808080, 0x80888888, + 0x00000000, 0x08000000, 0x0c300000, 0x00000006, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0000003c, 0xc03c0000, + 0x00006000, 0x06001e00, 0x60181860, 0x78000000, 0x00000000, 0x00000000, 0x0000001c, 0x18380090, + 0xb06060e0, 0xe0e0f800, 0xf088a888, 0x80808080, 0x90909090, 0x90b060e0, 0x808060e0, 0x80808888, + 0x00182428, 0x3e707018, 0x18180000, 0x00000006, 0x3c183c3c, 0x1c3e3c7e, 0x3c3c0000, 0x0200403c, + 0x3c187c1e, 0x787e7e1e, 0x663c7c66, 0x6066623c, 0x7c3c7c3c, 0x7e6266c2, 0x66667e30, 0xc00c1000, + 0x08006000, 0x06003000, 0x60181860, 0x18000000, 0x00000000, 0x10000000, 0x00000030, 0x180c0090, + 0x90101080, 0x80808818, 0x88f8a888, 0xe0807070, 0xe0e0e0e0, 0xe0901080, 0x70e01080, 0xe098f088, + 0x00182428, 0x6adad818, 0x18181000, 0x0000000c, 0x66386666, 0x2c3e667e, 0x66660000, 0x06006066, + 0x42186632, 0x6c606032, 0x66181864, 0x60667224, 0x66246666, 0x186262da, 0x62620630, 0x600c3800, + 0x10006000, 0x06003000, 0x60000060, 0x18000000, 0x00000000, 0x30000000, 0x00000030, 0x180c00e0, + 0x00e0e0f0, 0xf0f00018, 0x88889850, 0x80880808, 0x201c1c1c, 0x1c00e0f0, 0x0080e0f0, 0x80888888, + 0x00182428, 0x68dad808, 0x300c5418, 0x0000000c, 0x66580606, 0x2c206002, 0x66661818, 0x0cfe3006, + 0x9e2c6660, 0x66606060, 0x6618186c, 0x60667266, 0x66666660, 0x186262da, 0x36660c30, 0x600c2800, + 0x103c6c3c, 0x3e3c7e3e, 0x6c787866, 0x18d46c3c, 0x6c3e763c, 0x7e6666c2, 0x66667e18, 0x18180000, + 0x44180000, 0x18241c24, 0xf0888820, 0x8070f0f0, 0x20202020, 0x201c243e, 0x1cf8241c, 0x80708870, + 0x0018247c, 0x78745008, 0x300c3818, 0x00000018, 0x66180606, 0x4c206006, 0x76661818, 0x18fe180c, + 0xb62c6660, 0x66606060, 0x66181868, 0x607e5a66, 0x66666470, 0x186266da, 0x34340c30, 0x300c6c00, + 0x18667666, 0x66663066, 0x76181864, 0x18fe7666, 0x76663666, 0x306662da, 0x62620608, 0x1810323c, + 0x44247c7c, 0x24342042, 0x00000000, 0x00000000, 0x20202020, 0x20222408, 0x22002420, 0x00000000, + 0x00180028, 0x3c287610, 0x300cee7e, 0x00fe0018, 0x66180c18, 0x4c3c7c0c, 0x3c3e0000, 0x30000c18, + 0xb62c7c60, 0x667c7c6e, 0x7e181878, 0x605a5a66, 0x6466783c, 0x186234da, 0x18341830, 0x300c4400, + 0x18066660, 0x66663066, 0x66181868, 0x18d66666, 0x66663860, 0x306662da, 0x34620c30, 0x180c5a20, + 0x44241010, 0x242c2042, 0x0e3e103e, 0x3e3c1c3e, 0x3c1c1c1c, 0x1c3e1c08, 0x3e222418, 0x0e0e0e0e, + 0x0008007c, 0x1e5cdc00, 0x300c387e, 0x00fe0030, 0x66181806, 0x7e066618, 0x6e060000, 0x18001818, + 0xb67e6660, 0x66606066, 0x6618186c, 0x605a4e66, 0x78666c0e, 0x1862346c, 0x2c183030, 0x180c4400, + 0x003e6660, 0x667e3066, 0x66181878, 0x18d66666, 0x6666303c, 0x306634da, 0x18341808, 0x18104c38, + 0x3c181010, 0x18241c42, 0x11081008, 0x20222208, 0x00000000, 0x00220408, 0x22361804, 0x11111111, + 0x00000028, 0x16b6cc00, 0x300c5418, 0x00000030, 0x66183006, 0x7e066618, 0x66060000, 0x0cfe3000, + 0x9a466660, 0x66606066, 0x6618186c, 0x605a4e66, 0x60666606, 0x1862346c, 0x6c183030, 0x180c0000, + 0x00666660, 0x66603066, 0x6618186c, 0x18d66666, 0x66663006, 0x3066346c, 0x2c343018, 0x18180020, + 0x00091010, 0x000e0942, 0x10081008, 0x20222208, 0x0f06060f, 0x0a09041e, 0x002a0e38, 0x10101010, + 0x00180028, 0x56b6cc00, 0x300c1018, 0x18001860, 0x66187e66, 0x0c666630, 0x66661818, 0x06fe6018, + 0x40466632, 0x6c606036, 0x66181866, 0x605a4624, 0x60246666, 0x1834186c, 0x46186030, 0x0c0c0000, + 0x006e6666, 0x6e66306e, 0x66181866, 0x18d66666, 0x666e3066, 0x306e186c, 0x46186030, 0x180c003c, + 0x08090909, 0x1f110aff, 0x0e081008, 0x382c2208, 0x08020901, 0x0a0a0911, 0x09220907, 0x0e0e0e0e, + 0x00180028, 0x7c1c7600, 0x18180000, 0x18001860, 0x3c7e7e3c, 0x0c3c3c30, 0x3c3c1818, 0x02004018, + 0x3e467c1e, 0x787e601e, 0x663c1866, 0x7e42463c, 0x603c663c, 0x1818186c, 0x66187e30, 0x0c0c0000, + 0x00367c3c, 0x363c7c36, 0x667e1866, 0x7ed6663c, 0x7c367c3c, 0x1e36186c, 0x66187e30, 0x180c0008, + 0x080f0606, 0x04110c18, 0x01081008, 0x20222208, 0x0e020203, 0x0a0c0d1e, 0x0d220e08, 0x01010101, + 0x00000000, 0x10000000, 0x18180000, 0x080000c0, 0x00000000, 0x00000000, 0x00000008, 0x00000000, + 0x00000000, 0x00000000, 0x00001800, 0x00000000, 0x000c0000, 0x00000000, 0x00000030, 0x060c00fe, + 0x00000000, 0x00000006, 0x00001800, 0x00000000, 0x60060000, 0x00000000, 0x0010001c, 0x18380008, + 0x08090606, 0x040e0a18, 0x11081f08, 0x20221c3e, 0x08020401, 0x0f0a0b11, 0x0b220908, 0x11111111, + 0x00000000, 0x00000000, 0x0c300000, 0x080000c0, 0x00000000, 0x00000000, 0x00000008, 0x00000000, + 0x00000000, 0x00000000, 0x00007000, 0x00000000, 0x00060000, 0x00000000, 0x0000003c, 0x063c0000, + 0x00000000, 0x00000066, 0x00001800, 0x00000000, 0x60060000, 0x00000000, 0x00300000, 0x00000008, + 0x0f090909, 0x04030900, 0x0e000000, 0x00000000, 0x0f0f0f0f, 0x0209091e, 0x09000f07, 0x0e0e0e0e, + 0x00000000, 0x00000000, 0x00000000, 0x10000000, 0x00000000, 0x00000000, 0x00000010, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x0000003c, 0x00007000, 0x00000000, 0x60060000, 0x00000000, 0x00600000, 0x0000000f, + +}; + +static GBitmap strike0 = { + bits0, + 0, + 32, + 0, + {0, 0, 1024, 14}, + {0, 0, 1024, 14}, +}; + +static Fontchar info0[] = { + { 0, 0, 14, 0, 8 }, + { 8, 0, 14, 0, 8 }, + { 16, 0, 14, 0, 8 }, + { 24, 0, 14, 0, 8 }, + { 32, 0, 14, 0, 8 }, + { 40, 0, 14, 0, 8 }, + { 48, 0, 14, 0, 8 }, + { 56, 0, 14, 0, 8 }, + { 64, 0, 14, 0, 8 }, + { 72, 0, 14, 0, 8 }, + { 80, 0, 14, 0, 8 }, + { 88, 0, 14, 0, 8 }, + { 96, 0, 14, 0, 8 }, + { 104, 0, 14, 0, 8 }, + { 112, 0, 14, 0, 8 }, + { 120, 0, 14, 0, 8 }, + { 128, 0, 14, 0, 8 }, + { 136, 0, 14, 0, 8 }, + { 144, 0, 14, 0, 8 }, + { 152, 0, 14, 0, 8 }, + { 160, 0, 14, 0, 8 }, + { 168, 0, 14, 0, 8 }, + { 176, 0, 14, 0, 8 }, + { 184, 0, 14, 0, 8 }, + { 192, 0, 14, 0, 8 }, + { 200, 0, 14, 0, 8 }, + { 208, 0, 14, 0, 8 }, + { 216, 0, 14, 0, 8 }, + { 224, 0, 14, 0, 8 }, + { 232, 0, 14, 0, 8 }, + { 240, 0, 14, 0, 8 }, + { 248, 0, 14, 0, 8 }, + { 256, 0, 0, 0, 8 }, + { 264, 2, 11, 0, 8 }, + { 272, 2, 6, 0, 8 }, + { 280, 2, 11, 0, 8 }, + { 288, 1, 12, 0, 8 }, + { 296, 2, 11, 0, 8 }, + { 304, 2, 11, 0, 8 }, + { 312, 2, 7, 0, 8 }, + { 320, 1, 13, 0, 8 }, + { 328, 1, 13, 0, 8 }, + { 336, 3, 10, 0, 8 }, + { 344, 4, 10, 0, 8 }, + { 352, 9, 14, 0, 8 }, + { 360, 6, 8, 0, 8 }, + { 368, 9, 11, 0, 8 }, + { 376, 1, 13, 0, 8 }, + { 384, 2, 11, 0, 8 }, + { 392, 2, 11, 0, 8 }, + { 400, 2, 11, 0, 8 }, + { 408, 2, 11, 0, 8 }, + { 416, 2, 11, 0, 8 }, + { 424, 2, 11, 0, 8 }, + { 432, 2, 11, 0, 8 }, + { 440, 2, 11, 0, 8 }, + { 448, 2, 11, 0, 8 }, + { 456, 2, 11, 0, 8 }, + { 464, 4, 11, 0, 8 }, + { 472, 4, 14, 0, 8 }, + { 480, 2, 11, 0, 8 }, + { 488, 4, 10, 0, 8 }, + { 496, 2, 11, 0, 8 }, + { 504, 2, 11, 0, 8 }, + { 512, 2, 11, 0, 8 }, + { 520, 2, 11, 0, 8 }, + { 528, 2, 11, 0, 8 }, + { 536, 2, 11, 0, 8 }, + { 544, 2, 11, 0, 8 }, + { 552, 2, 11, 0, 8 }, + { 560, 2, 11, 0, 8 }, + { 568, 2, 11, 0, 8 }, + { 576, 2, 11, 0, 8 }, + { 584, 2, 11, 0, 8 }, + { 592, 2, 13, 0, 8 }, + { 600, 2, 11, 0, 8 }, + { 608, 2, 11, 0, 8 }, + { 616, 2, 11, 0, 8 }, + { 624, 2, 11, 0, 8 }, + { 632, 2, 11, 0, 8 }, + { 640, 2, 11, 0, 8 }, + { 648, 2, 13, 0, 8 }, + { 656, 2, 11, 0, 8 }, + { 664, 2, 11, 0, 8 }, + { 672, 2, 11, 0, 8 }, + { 680, 2, 11, 0, 8 }, + { 688, 2, 11, 0, 8 }, + { 696, 2, 11, 0, 8 }, + { 704, 2, 11, 0, 8 }, + { 712, 2, 11, 0, 8 }, + { 720, 2, 11, 0, 8 }, + { 728, 1, 13, 0, 8 }, + { 736, 1, 13, 0, 8 }, + { 744, 1, 13, 0, 8 }, + { 752, 2, 8, 0, 8 }, + { 760, 11, 12, 0, 8 }, + { 768, 2, 7, 0, 8 }, + { 776, 4, 11, 0, 8 }, + { 784, 1, 11, 0, 8 }, + { 792, 4, 11, 0, 8 }, + { 800, 1, 11, 0, 8 }, + { 808, 4, 11, 0, 8 }, + { 816, 1, 11, 0, 8 }, + { 824, 4, 14, 0, 8 }, + { 832, 1, 11, 0, 8 }, + { 840, 1, 11, 0, 8 }, + { 848, 1, 14, 0, 8 }, + { 856, 1, 11, 0, 8 }, + { 864, 1, 11, 0, 8 }, + { 872, 4, 11, 0, 8 }, + { 880, 4, 11, 0, 8 }, + { 888, 4, 11, 0, 8 }, + { 896, 4, 14, 0, 8 }, + { 904, 4, 14, 0, 8 }, + { 912, 4, 11, 0, 8 }, + { 920, 4, 11, 0, 8 }, + { 928, 2, 11, 0, 8 }, + { 936, 4, 11, 0, 8 }, + { 944, 4, 11, 0, 8 }, + { 952, 4, 11, 0, 8 }, + { 960, 4, 11, 0, 8 }, + { 968, 4, 14, 0, 8 }, + { 976, 4, 11, 0, 8 }, + { 984, 1, 12, 0, 8 }, + { 992, 1, 12, 0, 8 }, + { 1000, 1, 12, 0, 8 }, + { 1008, 5, 8, 0, 8 }, + { 1016, 0, 14, 0, 8 }, + { 1024, 0, 14, 0, 8 }, + { 0, 0, 0, 0, 0 } +}; + +GSubfont defont0 = { + 129, + 14, + 2, + info0, + &strike0, +}; diff --git a/os/boot/rpcg/devether.c b/os/boot/rpcg/devether.c new file mode 100644 index 00000000..c7a7a5dc --- /dev/null +++ b/os/boot/rpcg/devether.c @@ -0,0 +1,157 @@ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" + +#include "etherif.h" + +static Ctlr ether[MaxEther]; + +static struct { + char *type; + int (*reset)(Ctlr*); +} cards[] = { + { "SCC", sccethreset, }, + { "SCC2", sccethreset, }, + { 0, } +}; + +int +etherinit(void) +{ + Ctlr *ctlr; + int ctlrno, i, mask, n; + + mask = 0; + for(ctlrno = 0; ctlrno < MaxEther; ctlrno++){ + ctlr = ðer[ctlrno]; + memset(ctlr, 0, sizeof(Ctlr)); + if(archether(ctlrno, &ctlr->card) <= 0) + continue; + for(n = 0; cards[n].type; n++){ + if(strcmp(cards[n].type, ctlr->card.type)) + continue; + ctlr->ctlrno = ctlrno; + if((*cards[n].reset)(ctlr)) + break; + + ctlr->iq = qopen(16*1024, 1, 0, 0); + ctlr->oq = qopen(16*1024, 1, 0, 0); + + ctlr->present = 1; + mask |= 1<<ctlrno; + + print("ether%d: %s: port 0x%luX irq %d", + ctlr->ctlrno, ctlr->card.type, ctlr->card.port, ctlr->card.irq); + if(ctlr->card.mem) + print(" addr 0x%luX", PADDR(ctlr->card.mem)); + if(ctlr->card.size) + print(" size 0x%luX", ctlr->card.size); + print(":"); + for(i = 0; i < sizeof(ctlr->card.ea); i++) + print(" %2.2uX", ctlr->card.ea[i]); + print("\n"); uartwait(); + setvec(VectorPIC + ctlr->card.irq, ctlr->card.intr, ctlr); + break; + } + } + + return mask; +} + +static Ctlr* +attach(int ctlrno) +{ + Ctlr *ctlr; + + if(ctlrno >= MaxEther || ether[ctlrno].present == 0) + return 0; + + ctlr = ðer[ctlrno]; + if(ctlr->present == 1){ + ctlr->present = 2; + (*ctlr->card.attach)(ctlr); + } + + return ctlr; +} + +uchar* +etheraddr(int ctlrno) +{ + Ctlr *ctlr; + + if((ctlr = attach(ctlrno)) == 0) + return 0; + + return ctlr->card.ea; +} + +int +etherrxpkt(int ctlrno, Etherpkt *pkt, int timo) +{ + int n; + Ctlr *ctlr; + Block *b; + ulong start; + + if((ctlr = attach(ctlrno)) == 0) + return 0; + + start = m->ticks; + while((b = qget(ctlr->iq)) == 0){ + if(TK2MS(m->ticks - start) >= timo){ + /* + print("ether%d: rx timeout\n", ctlrno); + */ + return 0; + } + } + + n = BLEN(b); + memmove(pkt, b->rp, n); + freeb(b); + + return n; +} + +int +etheriq(Ctlr *ctlr, Block *b, int freebp) +{ + if(memcmp(((Etherpkt*)b->rp)->d, ctlr->card.ea, Eaddrlen) != 0 && + memcmp(((Etherpkt*)b->rp)->d, broadcast, Eaddrlen) != 0){ + if(freebp) + freeb(b); + return 0; + } + qbwrite(ctlr->iq, b); + return 1; +} + +int +ethertxpkt(int ctlrno, Etherpkt *pkt, int len, int) +{ + Ctlr *ctlr; + Block *b; + int s; + + if((ctlr = attach(ctlrno)) == 0) + return 0; + + if(qlen(ctlr->oq) > 16*1024){ + print("ether%d: tx queue full\n", ctlrno); + return 0; + } + b = iallocb(sizeof(Etherpkt)); + memmove(b->wp, pkt, len); + memmove(((Etherpkt*)b->wp)->s, ctlr->card.ea, Eaddrlen); + b->wp += len; + qbwrite(ctlr->oq, b); + s = splhi(); + (*ctlr->card.transmit)(ctlr); + splx(s); + + return 1; +} diff --git a/os/boot/rpcg/devuart.c b/os/boot/rpcg/devuart.c new file mode 100644 index 00000000..14e38592 --- /dev/null +++ b/os/boot/rpcg/devuart.c @@ -0,0 +1,230 @@ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" + +/* + * SMC1 in UART mode + */ + +typedef struct Uartsmc Uartsmc; +struct Uartsmc { + IOCparam; + ushort maxidl; + ushort idlc; + ushort brkln; + ushort brkec; + ushort brkcr; + ushort rmask; +}; + +typedef struct Uart Uart; +struct Uart +{ + int port; + int setup; + uchar txbusy; + + Queue* iq; + Queue* oq; + void (*rx)(Queue*, int); + void (*boot)(uchar*, int); + + ulong frame; + ulong overrun; + uchar rxbuf[128]; + char txbuf[16]; + BD* rxb; + BD* txb; +}; + +Uart uart[1]; +int predawn = 1; + +static void uartintr(Ureg*, void*); +static void uartkick(void*); + +static int +baudgen(int baud) +{ + int d; + + d = ((m->cpuhz/baud)+8)>>4; + if(d >= (1<<12)) + return ((d+15)>>3)|1; + return d<<1; +} + +static void +smcsetup(Uart *up, int baud) +{ + IMM *io; + Uartsmc *p; + BD *bd; + SMC *smc; + + archenableuart(SMC1ID, 0); + io = m->iomem; + io->pbpar |= IBIT(24)|IBIT(25); /* enable SMC1 TX/RX */ + io->pbdir &= ~(IBIT(24)|IBIT(25)); + io->brgc1 = baudgen(baud) | BaudEnable; + io->simode &= ~0xF000; /* SMC1 to NMSI mode, Tx/Rx clocks are BRG1 */ + + bd = bdalloc(1); + p = (Uartsmc*)KADDR(SMC1P); + p->rbase = (ushort)bd; + up->rxb = bd; + bd->status = BDEmpty|BDWrap|BDInt; + bd->length = 0; + bd->addr = PADDR(up->rxbuf); + bd = bdalloc(1); + p->tbase = (ushort)bd; + up->txb = bd; + bd->status = BDWrap|BDInt; + bd->length = 0; + bd->addr = PADDR(up->txbuf); + + cpmop(InitRxTx, SMC1ID, 0); + + /* protocol parameters */ + p->rfcr = 0x18; + p->tfcr = 0x18; + p->mrblr = 1; + p->maxidl = 1; + p->brkln = 0; + p->brkec = 0; + p->brkcr = 1; + smc = IOREGS(0xA80, SMC); + smc->smce = 0xff; /* clear events */ + smc->smcm = 0x17; /* enable all possible interrupts */ + setvec(VectorCPIC+4, uartintr, up); + smc->smcmr = 0x4820; /* 8-bit mode, no parity, 1 stop bit, UART mode, ... */ + smc->smcmr |= 3; /* enable rx/tx */ +} + +static void +uartintr(Ureg*, void *arg) +{ + Uart *up; + int ch, i; + BD *bd; + SMC *smc; + Block *b; + + up = arg; + smc = IOREGS(0xA80, SMC); + smc->smce = 0xff; /* clear all events */ + if((bd = up->rxb) != nil && (bd->status & BDEmpty) == 0){ + if(up->iq != nil && bd->length > 0){ + if(up->boot != nil){ + up->boot(up->rxbuf, bd->length); + }else if(up->rx != nil){ + for(i=0; i<bd->length; i++){ + ch = up->rxbuf[i]; + up->rx(up->iq, ch); + } + }else{ + b = iallocb(bd->length); + memmove(b->wp, up->rxbuf, bd->length); + b->wp += bd->length; + qbwrite(up->iq, b); + } + } + bd->status |= BDEmpty|BDInt; + } else if((bd = up->txb) != nil && (bd->status & BDReady) == 0){ + ch = -1; + if(up->oq) + ch = qbgetc(up->oq); + if(ch != -1){ + up->txbuf[0] = ch; + bd->length = 1; + bd->status |= BDReady; + }else + up->txbusy = 0; + } + /* TO DO: modem status, errors, etc */ +} + +static void +uartkick(void *arg) +{ + Uart *up = arg; + int s, c, i; + + s = splhi(); + while(up->txbusy == 0 && (c = qbgetc(up->oq)) != -1){ + if(predawn){ + while(up->txb->status & BDReady) + ; + } else { + for(i = 0; i < 100; i++){ + if((up->txb->status & BDReady) == 0) + break; + delay(1); + } + } + up->txbuf[0] = c; + up->txb->length = 1; + up->txb->status |= BDReady; + up->txbusy = !predawn; + } + splx(s); +} + +void +uartspecial(int port, int baud, Queue **iq, Queue **oq, void (*rx)(Queue*,int)) +{ + Uart *up = &uart[0]; + + if(up->setup) + return; + up->setup = 1; + + *iq = up->iq = qopen(4*1024, 0, 0, 0); + *oq = up->oq = qopen(16*1024, 0, uartkick, up); + up->rx = rx; + USED(port); + up->port = SMC1ID; + if(baud == 0) + baud = 9600; + smcsetup(up, baud); + /* if using SCCn's UART, would also set DTR and RTS, but SMC doesn't use them */ +} + +void +uartsetboot(void (*f)(uchar*, int)) +{ + uart[0].boot = f; +} + +void +uartputs(char *s, int n) +{ + Uart *up = &uart[0]; + Block *b; + int nl; + char *p; + + nl = 0; + for(p = s; p < s+n; p++) + if(*p == '\n') + nl++; + b = iallocb(n+nl); + while(n--){ + if(*s == '\n') + *b->wp++ = '\r'; + *b->wp++ = *s++; + } + qbwrite(up->oq, b); +} + +void +uartwait(void) +{ + Uart *up = &uart[0]; + + while(up->txbusy) + ; +} diff --git a/os/boot/rpcg/dload.c b/os/boot/rpcg/dload.c new file mode 100644 index 00000000..c05423a2 --- /dev/null +++ b/os/boot/rpcg/dload.c @@ -0,0 +1,103 @@ +#include <u.h> +#include <libc.h> +#include <bio.h> +#include <mach.h> + +static char *kernelfile = "/power/ipaq"; +ulong crc32(void *buf, int n, ulong crc); + +void +main(int argc, char **argv) +{ + int ifd, n; + char buf[64], reply[1]; + int i, execsize; + Fhdr f; + ulong csum; + + ARGBEGIN{ + }ARGEND + ifd = open(kernelfile, OREAD); + if(ifd < 0){ + fprint(2, "dload: can't open %s: %r\n", kernelfile); + exits("open"); + } + i = 0; + if(crackhdr(ifd, &f) == 0){ + fprint(2, "dload: not an executable file: %r\n"); + exits("format"); + } + if(f.magic != Q_MAGIC){ + fprint(2, "dload: not a powerpc executable\n"); + exits("format"); + } + execsize = f.txtsz + f.datsz + f.txtoff; + seek(ifd, 0, 0); + csum = ~0; + while(execsize > 0 && (n = read(ifd, buf, sizeof(buf))) > 0){ + if(n > execsize) + n = execsize; + for(;;){ + if(write(1, buf, sizeof(buf)) != sizeof(buf)){ /* always writes full buffer */ + fprint(2, "dload: write error: %r\n"); + exits("write"); + } + if(read(0, reply, 1) != 1){ + fprint(2, "dload: bad reply\n"); + exits("read"); + } + if(reply[0] != 'n') + break; + fprint(2, "!"); + } + if(reply[0] != 'y'){ + fprint(2, "dload: bad ack: %c\n", reply[0]); + exits("reply"); + } + if(++i%10 == 0) + fprint(2, "."); + execsize -= n; + } + exits(0); +} + +/* + * from Rob Warnock + */ +static ulong crc32tab[256]; /* initialised on first call to crc32 */ + +enum { + CRC32POLY = 0x04c11db7 /* AUTODIN II, Ethernet, & FDDI */ +}; + +/* + * Build auxiliary table for parallel byte-at-a-time CRC-32. + */ +static void +initcrc32(void) +{ + int i, j; + ulong c; + + for(i = 0; i < 256; i++) { + for(c = i << 24, j = 8; j > 0; j--) + if(c & (1<<31)) + c = (c<<1) ^ CRC32POLY; + else + c <<= 1; + crc32tab[i] = c; + } +} + +ulong +crc32(void *buf, int n, ulong crc) +{ + uchar *p; + + if(crc32tab[1] == 0) + initcrc32(); + crc = ~crc; + for(p = buf; --n >= 0;) + crc = (crc << 8) ^ crc32tab[(crc >> 24) ^ *p++]; + return ~crc; +} diff --git a/os/boot/rpcg/donprint.c b/os/boot/rpcg/donprint.c new file mode 100644 index 00000000..4125e690 --- /dev/null +++ b/os/boot/rpcg/donprint.c @@ -0,0 +1,332 @@ +#include "u.h" +#include "lib.h" + +#define PTR sizeof(char*) +#define SHORT sizeof(int) +#define INT sizeof(int) +#define LONG sizeof(long) +#define IDIGIT 30 +#define MAXCON 30 + +#define FLONG (1<<0) +#define FSHORT (1<<1) +#define FUNSIGN (1<<2) + +typedef struct Op Op; +struct Op +{ + char *p; + char *ep; + void *argp; + int f1; + int f2; + int f3; +}; + +static int noconv(Op*); +static int cconv(Op*); +static int dconv(Op*); +static int hconv(Op*); +static int lconv(Op*); +static int oconv(Op*); +static int sconv(Op*); +static int uconv(Op*); +static int xconv(Op*); +static int Xconv(Op*); +static int percent(Op*); + +static +int (*fmtconv[MAXCON])(Op*) = +{ + noconv, + cconv, dconv, hconv, lconv, + oconv, sconv, uconv, xconv, + Xconv, percent, +}; +static +char fmtindex[128] = +{ + ['c'] 1, + ['d'] 2, + ['h'] 3, + ['l'] 4, + ['o'] 5, + ['s'] 6, + ['u'] 7, + ['x'] 8, + ['X'] 9, + ['%'] 10, +}; + +static int convcount = { 11 }; +static int ucase; + +static void +PUT(Op *o, int c) +{ + static int pos; + int opos; + + if(c == '\t'){ + opos = pos; + pos = (opos+8) & ~7; + while(opos++ < pos && o->p < o->ep) + *o->p++ = ' '; + return; + } + if(o->p < o->ep){ + *o->p++ = c; + pos++; + } + if(c == '\n') + pos = 0; +} + +int +fmtinstall(char c, int (*f)(Op*)) +{ + + c &= 0177; + if(fmtindex[c] == 0) { + if(convcount >= MAXCON) + return 1; + fmtindex[c] = convcount++; + } + fmtconv[fmtindex[c]] = f; + return 0; +} + +char* +donprint(char *p, char *ep, char *fmt, void *argp) +{ + int sf1, c; + Op o; + + o.p = p; + o.ep = ep; + o.argp = argp; + +loop: + c = *fmt++; + if(c != '%') { + if(c == 0) { + if(o.p < o.ep) + *o.p = 0; + return o.p; + } + PUT(&o, c); + goto loop; + } + o.f1 = 0; + o.f2 = -1; + o.f3 = 0; + c = *fmt++; + sf1 = 0; + if(c == '-') { + sf1 = 1; + c = *fmt++; + } + while(c >= '0' && c <= '9') { + o.f1 = o.f1*10 + c-'0'; + c = *fmt++; + } + if(sf1) + o.f1 = -o.f1; + if(c != '.') + goto l1; + c = *fmt++; + while(c >= '0' && c <= '9') { + if(o.f2 < 0) + o.f2 = 0; + o.f2 = o.f2*10 + c-'0'; + c = *fmt++; + } +l1: + if(c == 0) + fmt--; + c = (*fmtconv[fmtindex[c&0177]])(&o); + if(c < 0) { + o.f3 |= -c; + c = *fmt++; + goto l1; + } + o.argp = (char*)o.argp + c; + goto loop; +} + +void +strconv(char *o, Op *op, int f1, int f2) +{ + int n, c; + char *p; + + n = strlen(o); + if(f1 >= 0) + while(n < f1) { + PUT(op, ' '); + n++; + } + for(p=o; c = *p++;) + if(f2 != 0) { + PUT(op, c); + f2--; + } + if(f1 < 0) { + f1 = -f1; + while(n < f1) { + PUT(op, ' '); + n++; + } + } +} + +int +numbconv(Op *op, int base) +{ + char b[IDIGIT]; + int i, f, n, r; + long v; + short h; + + f = 0; + switch(op->f3 & (FLONG|FSHORT|FUNSIGN)) { + case FLONG: + v = *(long*)op->argp; + r = LONG; + break; + + case FUNSIGN|FLONG: + v = *(ulong*)op->argp; + r = LONG; + break; + + case FSHORT: + h = *(int*)op->argp; + v = h; + r = SHORT; + break; + + case FUNSIGN|FSHORT: + h = *(int*)op->argp; + v = (ushort)h; + r = SHORT; + break; + + default: + v = *(int*)op->argp; + r = INT; + break; + + case FUNSIGN: + v = *(unsigned*)op->argp; + r = INT; + break; + } + if(!(op->f3 & FUNSIGN) && v < 0) { + v = -v; + f = 1; + } + b[IDIGIT-1] = 0; + for(i = IDIGIT-2;; i--) { + n = (ulong)v % base; + n += '0'; + if(n > '9'){ + n += 'a' - ('9'+1); + if(ucase) + n += 'A'-'a'; + } + b[i] = n; + if(i < 2) + break; + v = (ulong)v / base; + if(op->f2 >= 0 && i >= IDIGIT-op->f2) + continue; + if(v <= 0) + break; + } + if(f) + b[--i] = '-'; + strconv(b+i, op, op->f1, -1); + return r; +} + +static int +noconv(Op *op) +{ + + strconv("***", op, 0, -1); + return 0; +} + +static int +cconv(Op *op) +{ + char b[2]; + + b[0] = *(int*)op->argp; + b[1] = 0; + strconv(b, op, op->f1, -1); + return INT; +} + +static int +dconv(Op *op) +{ + return numbconv(op, 10); +} + +static int +hconv(Op*) +{ + return -FSHORT; +} + +static int +lconv(Op*) +{ + return -FLONG; +} + +static int +oconv(Op *op) +{ + return numbconv(op, 8); +} + +static int +sconv(Op *op) +{ + strconv(*(char**)op->argp, op, op->f1, op->f2); + return PTR; +} + +static int +uconv(Op*) +{ + return -FUNSIGN; +} + +static int +xconv(Op *op) +{ + return numbconv(op, 16); +} + +static int +Xconv(Op *op) +{ + int r; + + ucase = 1; + r = numbconv(op, 16); + ucase = 0; + return r; +} + +static int +percent(Op *op) +{ + + PUT(op, '%'); + return 0; +} diff --git a/os/boot/rpcg/dosboot.c b/os/boot/rpcg/dosboot.c new file mode 100644 index 00000000..cd8d1276 --- /dev/null +++ b/os/boot/rpcg/dosboot.c @@ -0,0 +1,614 @@ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "dosfs.h" + +extern char *premature; + +/* + * predeclared + */ +static void bootdump(Dosboot*); +static void setname(Dosfile*, char*); +long dosreadseg(Dosfile*, long, long); + +/* + * debugging + */ +#define chatty 1 +#define chat if(chatty)print + +/* + * block io buffers + */ +enum +{ + Nbio= 16, +}; +typedef struct Clustbuf Clustbuf; +struct Clustbuf +{ + int age; + long sector; + uchar *iobuf; + Dos *dos; + int size; +}; +Clustbuf bio[Nbio]; + +/* + * get an io block from an io buffer + */ +Clustbuf* +getclust(Dos *dos, long sector) +{ + Clustbuf *p, *oldest; + int size; + + chat("getclust @ %d\n", sector); + + /* + * if we have it, just return it + */ + for(p = bio; p < &bio[Nbio]; p++){ + if(sector == p->sector && dos == p->dos){ + p->age = m->ticks; + chat("getclust %d in cache\n", sector); + return p; + } + } + + /* + * otherwise, reuse the oldest entry + */ + oldest = bio; + for(p = &bio[1]; p < &bio[Nbio]; p++){ + if(p->age <= oldest->age) + oldest = p; + } + p = oldest; + + /* + * make sure the buffer is big enough + */ + size = dos->clustsize*dos->sectsize; + if(p->iobuf==0 || p->size < size) + p->iobuf = ialloc(size, 0); + p->size = size; + + /* + * read in the cluster + */ + chat("getclust addr %d\n", (sector+dos->start)*dos->sectsize); + if((*dos->seek)(dos->dev, (sector+dos->start)*dos->sectsize) < 0){ + chat("can't seek block\n"); + return 0; + } + if((*dos->read)(dos->dev, p->iobuf, size) != size){ + chat("can't read block\n"); + return 0; + } + + p->age = m->ticks; + p->dos = dos; + p->sector = sector; + chat("getclust %d read\n", sector); + return p; +} + +/* + * walk the fat one level ( n is a current cluster number ). + * return the new cluster number or -1 if no more. + */ +static long +fatwalk(Dos *dos, int n) +{ + ulong k, sect; + Clustbuf *p; + int o; + + chat("fatwalk %d\n", n); + + if(n < 2 || n >= dos->fatclusters) + return -1; + + switch(dos->fatbits){ + case 12: + k = (3*n)/2; break; + case 16: + k = 2*n; break; + default: + return -1; + } + if(k >= dos->fatsize*dos->sectsize) + panic("getfat"); + + sect = (k/(dos->sectsize*dos->clustsize))*dos->clustsize + dos->fataddr; + o = k%(dos->sectsize*dos->clustsize); + p = getclust(dos, sect); + k = p->iobuf[o++]; + if(o >= dos->sectsize*dos->clustsize){ + p = getclust(dos, sect+dos->clustsize); + o = 0; + } + k |= p->iobuf[o]<<8; + if(dos->fatbits == 12){ + if(n&1) + k >>= 4; + else + k &= 0xfff; + if(k >= 0xff8) + k |= 0xf000; + } + k = k < 0xfff8 ? k : -1; + chat("fatwalk %d -> %d\n", n, k); + return k; +} + +/* + * map a file's logical cluster address to a physical sector address + */ +static long +fileaddr(Dosfile *fp, long ltarget) +{ + Dos *dos = fp->dos; + long l; + long p; + + chat("fileaddr %8.8s %d\n", fp->name, ltarget); + /* + * root directory is contiguous and easy + */ + if(fp->pstart == 0){ + if(ltarget*dos->sectsize*dos->clustsize >= dos->rootsize*sizeof(Dosdir)) + return -1; + l = dos->rootaddr + ltarget*dos->clustsize; + chat("fileaddr %d -> %d\n", ltarget, l); + return l; + } + + /* + * anything else requires a walk through the fat + */ + if(ltarget >= fp->lcurrent && fp->pcurrent){ + /* start at the currrent point */ + l = fp->lcurrent; + p = fp->pcurrent; + } else { + /* go back to the beginning */ + l = 0; + p = fp->pstart; + } + while(l != ltarget){ + /* walk the fat */ + p = fatwalk(dos, p); + if(p < 0) + return -1; + l++; + } + fp->lcurrent = l; + fp->pcurrent = p; + + /* + * clusters start at 2 instead of 0 (why? - presotto) + */ + l = dos->dataaddr + (p-2)*dos->clustsize; + chat("fileaddr %d -> %d\n", ltarget, l); + return l; +} + +/* + * read from a dos file + */ +long +dosread(Dosfile *fp, void *a, long n) +{ + long addr; + long rv; + int i; + int off; + Clustbuf *p; + uchar *from, *to; + + if((fp->attr & DDIR) == 0){ + if(fp->offset >= fp->length) + return 0; + if(fp->offset+n > fp->length) + n = fp->length - fp->offset; + } + + to = a; + for(rv = 0; rv < n; rv+=i){ + /* + * read the cluster + */ + addr = fileaddr(fp, fp->offset/fp->dos->clustbytes); + if(addr < 0) + return -1; + p = getclust(fp->dos, addr); + if(p == 0) + return -1; + + /* + * copy the bytes we need + */ + off = fp->offset % fp->dos->clustbytes; + from = &p->iobuf[off]; + i = n - rv; + if(i > fp->dos->clustbytes - off) + i = fp->dos->clustbytes - off; + memmove(to, from, i); + to += i; + fp->offset += i; + } + + return rv; +} + +/* + * walk a directory returns + * -1 if something went wrong + * 0 if not found + * 1 if found + */ +int +doswalk(Dosfile *file, char *name) +{ + Dosdir d; + long n; + + if((file->attr & DDIR) == 0){ + chat("walking non-directory!\n"); + return -1; + } + + setname(file, name); + + file->offset = 0; /* start at the beginning */ + while((n = dosread(file, &d, sizeof(d))) == sizeof(d)){ + chat("comparing to %8.8s.%3.3s\n", d.name, d.ext); + if(memcmp(file->name, d.name, sizeof(d.name)) != 0) + continue; + if(memcmp(file->ext, d.ext, sizeof(d.ext)) != 0) + continue; + if(d.attr & DVLABEL){ + chat("%8.8s.%3.3s is a LABEL\n", d.name, d.ext); + continue; + } + file->attr = d.attr; + file->pstart = GSHORT(d.start); + file->length = GLONG(d.length); + file->pcurrent = 0; + file->lcurrent = 0; + file->offset = 0; + return 1; + } + return n >= 0 ? 0 : -1; +} + + +/* + * instructions that boot blocks can start with + */ +#define JMPSHORT 0xeb +#define JMPNEAR 0xe9 + +/* + * read dos file system properties + */ +int +dosinit(Dos *dos, int start, int ishard) +{ + Dosboot *b; + int i; + Clustbuf *p; + Dospart *dp; + ulong mbroffset, offset; + + /* defaults till we know better */ + dos->start = start; + dos->sectsize = 512; + dos->clustsize = 1; + mbroffset = 0; + +dmddo: + /* get first sector */ + p = getclust(dos, mbroffset); + if(p == 0){ + chat("can't read boot block\n"); + return -1; + } + + /* + * If it's a hard disc then look for an MBR and pick either an + * active partition or the FAT with the lowest starting LBA. + * Things are tricky because we could be pointing to, amongst others: + * 1) a floppy BPB; + * 2) a hard disc MBR; + * 3) a hard disc extended partition table; + * 4) a logical drive on a hard disc; + * 5) a disc-manager boot block. + * They all have the same magic at the end of the block. + */ + if(p->iobuf[0x1FE] != 0x55 || p->iobuf[0x1FF] != 0xAA) { + chat("not DOS\n"); + return -1; + } + p->dos = 0; + b = (Dosboot *)p->iobuf; + if(ishard && b->mediadesc != 0xF8){ + dp = (Dospart*)&p->iobuf[0x1BE]; + offset = 0xFFFFFFFF; + for(i = 0; i < 4; i++, dp++){ + if(dp->type == DMDDO){ + mbroffset = 63; + goto dmddo; + } + if(dp->type != FAT12 && dp->type != FAT16 && dp->type != FATHUGE) + continue; + if(dp->flag & 0x80){ + offset = GLONG(dp->start); + break; + } + if(GLONG(dp->start) < offset) + offset = GLONG(dp->start); + } + if(i != 4 || offset != 0xFFFFFFFF){ + dos->start = mbroffset+offset; + p = getclust(dos, 0); + if(p == 0 || p->iobuf[0x1FE] != 0x55 || p->iobuf[0x1FF] != 0xAA) + return -1; + } + p->dos = 0; + } + + b = (Dosboot *)p->iobuf; + if(b->magic[0] != JMPNEAR && (b->magic[0] != JMPSHORT || b->magic[2] != 0x90)){ + chat("no dos file system\n"); + return -1; + } + + if(chatty) + bootdump(b); + + /* + * determine the systems' wondersous properties + */ + dos->sectsize = GSHORT(b->sectsize); + dos->clustsize = b->clustsize; + dos->clustbytes = dos->sectsize*dos->clustsize; + dos->nresrv = GSHORT(b->nresrv); + dos->nfats = b->nfats; + dos->rootsize = GSHORT(b->rootsize); + dos->volsize = GSHORT(b->volsize); + if(dos->volsize == 0) + dos->volsize = GLONG(b->bigvolsize); + dos->mediadesc = b->mediadesc; + dos->fatsize = GSHORT(b->fatsize); + dos->fataddr = dos->nresrv; + dos->rootaddr = dos->fataddr + dos->nfats*dos->fatsize; + i = dos->rootsize*sizeof(Dosdir) + dos->sectsize - 1; + i = i/dos->sectsize; + dos->dataaddr = dos->rootaddr + i; + dos->fatclusters = 2+(dos->volsize - dos->dataaddr)/dos->clustsize; + if(dos->fatclusters < 4087) + dos->fatbits = 12; + else + dos->fatbits = 16; + dos->freeptr = 2; + + /* + * set up the root + */ + dos->root.dos = dos; + dos->root.pstart = 0; + dos->root.pcurrent = dos->root.lcurrent = 0; + dos->root.offset = 0; + dos->root.attr = DDIR; + dos->root.length = dos->rootsize*sizeof(Dosdir); + + return 0; +} + +static void +bootdump(Dosboot *b) +{ + if(chatty == 0) + return; + print("magic: 0x%2.2x 0x%2.2x 0x%2.2x\n", + b->magic[0], b->magic[1], b->magic[2]); + print("version: \"%8.8s\"\n", b->version); + print("sectsize: %d\n", GSHORT(b->sectsize)); + print("allocsize: %d\n", b->clustsize); + print("nresrv: %d\n", GSHORT(b->nresrv)); + print("nfats: %d\n", b->nfats); + print("rootsize: %d\n", GSHORT(b->rootsize)); + print("volsize: %d\n", GSHORT(b->volsize)); + print("mediadesc: 0x%2.2x\n", b->mediadesc); + print("fatsize: %d\n", GSHORT(b->fatsize)); + print("trksize: %d\n", GSHORT(b->trksize)); + print("nheads: %d\n", GSHORT(b->nheads)); + print("nhidden: %d\n", GLONG(b->nhidden)); + print("bigvolsize: %d\n", GLONG(b->bigvolsize)); + print("driveno: %d\n", b->driveno); + print("reserved0: 0x%2.2x\n", b->reserved0); + print("bootsig: 0x%2.2x\n", b->bootsig); + print("volid: 0x%8.8x\n", GLONG(b->volid)); + print("label: \"%11.11s\"\n", b->label); +} + +/* + * grab next element from a path, return the pointer to unprocessed portion of + * path. + */ +static 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==28){ + print("name component too long\n"); + return 0; + } + *elem++ = *path++; + } + *elem = '\0'; + return path; +} + +int +dosstat(Dos *dos, char *path, Dosfile *f) +{ + char element[NAMELEN]; + + *f = dos->root; + while(path = nextelem(path, element)){ + switch(doswalk(f, element)){ + case -1: + return -1; + case 0: + return 0; + } + } + return 1; +} + +/* + * boot + */ +int +dosboot(Dos *dos, char *path) +{ + Dosfile file; + long n; + long addr; + Exec *ep; + void (*b)(void); + + switch(dosstat(dos, 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 %8.8s.%3.3s attr 0x%ux start 0x%lux len %d\n", file.name, + file.ext, file.attr, file.pstart, file.length); + break; + } + + /* + * read header + */ + ep = (Exec*)ialloc(sizeof(Exec), 0); + n = sizeof(Exec); + if(dosreadseg(&file, n, (ulong) ep) != n){ + print(premature); + return -1; + } + if(GLLONG(ep->magic) != Q_MAGIC){ + print("bad magic 0x%lux not a plan 9 executable!\n", GLLONG(ep->magic)); + return -1; + } + + /* + * read text + */ + addr = PADDR(GLLONG(ep->entry)); + n = GLLONG(ep->text); + print("+%d", n); + if(dosreadseg(&file, n, addr) != n){ + print(premature); + return -1; + } + + /* + * read data (starts at first page after kernel) + */ + addr = PGROUND(addr+n); + n = GLLONG(ep->data); + print("+%d", n); + if(dosreadseg(&file, n, addr) != n){ + print(premature); + return -1; + } + + /* + * bss and entry point + */ + print("+%d\nstart at 0x%lux\n", GLLONG(ep->bss), GLLONG(ep->entry)); + + /* + * Go to new code. It's up to the program to get its PC relocated to + * the right place. + */ + b = (void (*)(void))(PADDR(GLLONG(ep->entry))); + (*b)(); + return 0; +} + +/* + * read in a segment + */ +long +dosreadseg(Dosfile *fp, long len, long addr) +{ + char *a; + long n, sofar; + + a = (char *)addr; + for(sofar = 0; sofar < len; sofar += n){ + n = 8*1024; + if(len - sofar < n) + n = len - sofar; + n = dosread(fp, a + sofar, n); + if(n <= 0) + break; + print("."); + } + return sofar; +} + +/* + * set up a dos file name + */ +static void +setname(Dosfile *fp, char *from) +{ + char *to; + + to = fp->name; + for(; *from && to-fp->name < 8; from++, to++){ + if(*from == '.'){ + from++; + break; + } + if(*from >= 'a' && *from <= 'z') + *to = *from + 'A' - 'a'; + else + *to = *from; + } + while(to - fp->name < 8) + *to++ = ' '; + + to = fp->ext; + for(; *from && to-fp->ext < 3; from++, to++){ + if(*from >= 'a' && *from <= 'z') + *to = *from + 'A' - 'a'; + else + *to = *from; + } + while(to-fp->ext < 3) + *to++ = ' '; + + chat("name is %8.8s %3.3s\n", fp->name, fp->ext); +} diff --git a/os/boot/rpcg/dosfs.h b/os/boot/rpcg/dosfs.h new file mode 100644 index 00000000..a45065a6 --- /dev/null +++ b/os/boot/rpcg/dosfs.h @@ -0,0 +1,110 @@ +typedef struct Dosboot Dosboot; +typedef struct Dos Dos; +typedef struct Dosdir Dosdir; +typedef struct Dosfile Dosfile; +typedef struct Dospart Dospart; + +struct Dospart +{ + uchar flag; /* active flag */ + uchar shead; /* starting head */ + uchar scs[2]; /* starting cylinder/sector */ + uchar type; /* partition type */ + uchar ehead; /* ending head */ + uchar ecs[2]; /* ending cylinder/sector */ + uchar start[4]; /* starting sector */ + uchar len[4]; /* length in sectors */ +}; + +#define FAT12 0x01 +#define FAT16 0x04 +#define FATHUGE 0x06 +#define DMDDO 0x54 + +struct Dosboot{ + uchar magic[3]; + uchar version[8]; + uchar sectsize[2]; + uchar clustsize; + uchar nresrv[2]; + uchar nfats; + uchar rootsize[2]; + uchar volsize[2]; + uchar mediadesc; + uchar fatsize[2]; + uchar trksize[2]; + uchar nheads[2]; + uchar nhidden[4]; + uchar bigvolsize[4]; + uchar driveno; + uchar reserved0; + uchar bootsig; + uchar volid[4]; + uchar label[11]; + uchar reserved1[8]; +}; + +struct Dosfile{ + Dos *dos; /* owning dos file system */ + char name[8]; + char ext[3]; + uchar attr; + long length; + long pstart; /* physical start cluster address */ + long pcurrent; /* physical current cluster address */ + long lcurrent; /* logical current cluster address */ + long offset; +}; + +struct Dos{ + int dev; /* device id */ + long (*read)(int, void*, long); /* read routine */ + long (*seek)(int, long); /* seek routine */ + + int start; /* start of file system */ + int sectsize; /* in bytes */ + int clustsize; /* in sectors */ + int clustbytes; /* in bytes */ + int nresrv; /* sectors */ + int nfats; /* usually 2 */ + int rootsize; /* number of entries */ + int volsize; /* in sectors */ + int mediadesc; + int fatsize; /* in sectors */ + int fatclusters; + int fatbits; /* 12 or 16 */ + long fataddr; /* sector number */ + long rootaddr; + long dataaddr; + long freeptr; + + Dosfile root; +}; + +struct Dosdir{ + uchar name[8]; + uchar ext[3]; + uchar attr; + uchar reserved[10]; + uchar time[2]; + uchar date[2]; + uchar start[2]; + uchar length[4]; +}; + +#define DRONLY 0x01 +#define DHIDDEN 0x02 +#define DSYSTEM 0x04 +#define DVLABEL 0x08 +#define DDIR 0x10 +#define DARCH 0x20 + +extern int chatty; + +extern int dosboot(Dos*, char*); +extern int dosinit(Dos*, int, int); +extern long dosread(Dosfile*, void*, long); +extern int dosstat(Dos*, char*, Dosfile*); +extern int doswalk(Dosfile*, char*); + +extern int plan9ini(Dos*, char*); diff --git a/os/boot/rpcg/etherif.h b/os/boot/rpcg/etherif.h new file mode 100644 index 00000000..a4e790a6 --- /dev/null +++ b/os/boot/rpcg/etherif.h @@ -0,0 +1,59 @@ +/* + * All the goo for PC ethernet cards. + */ +typedef struct Card Card; +typedef struct Type Type; +typedef struct Ctlr Ctlr; + +/* + * Hardware interface. + */ +struct Card { + ISAConf; + + int (*reset)(Ctlr*); + void (*attach)(Ctlr*); + + void *(*read)(Ctlr*, void*, ulong, ulong); + void *(*write)(Ctlr*, ulong, void*, ulong); + + void (*receive)(Ctlr*); + void (*transmit)(Ctlr*); + void (*intr)(Ureg*, void*); + void (*overflow)(Ctlr*); + + uchar bit16; /* true if a 16 bit interface */ + uchar ram; /* true if card has shared memory */ + + ulong dp8390; /* I/O address of 8390 (if any) */ + ulong data; /* I/O data port if no shared memory */ + uchar nxtpkt; /* software bndry */ + uchar tstart; /* 8390 ring addresses */ + uchar pstart; + uchar pstop; + + uchar dummyrr; /* do dummy remote read */ +}; + +/* + * Software controller. + */ +struct Ctlr { + Card card; /* hardware info */ + int ctlrno; + int present; + + Queue* iq; + Queue* oq; + + int inpackets; + int outpackets; + int crcs; /* input crc errors */ + int oerrs; /* output errors */ + int frames; /* framing errors */ + int overflows; /* packet overflows */ + int buffs; /* buffering errors */ +}; + +extern int sccethreset(Ctlr*); +extern int etheriq(Ctlr*, Block*, int); diff --git a/os/boot/rpcg/etherscc.c b/os/boot/rpcg/etherscc.c new file mode 100644 index 00000000..1e47d473 --- /dev/null +++ b/os/boot/rpcg/etherscc.c @@ -0,0 +1,411 @@ +/* + * SCCn ethernet + */ + +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" + +#include "etherif.h" + +enum { + Nrdre = 32, /* receive descriptor ring entries */ + Ntdre = 4, /* transmit descriptor ring entries */ + + Rbsize = ETHERMAXTU+4, /* ring buffer size (+4 for CRC) */ + Bufsize = (Rbsize+7)&~7, /* aligned */ +}; + +enum { + /* ether-specific Rx BD bits */ + RxMiss= 1<<8, + RxeLG= 1<<5, + RxeNO= 1<<4, + RxeSH= 1<<3, + RxeCR= 1<<2, + RxeOV= 1<<1, + RxeCL= 1<<0, + RxError= (RxeLG|RxeNO|RxeSH|RxeCR|RxeOV|RxeCL), /* various error flags */ + + /* ether-specific Tx BD bits */ + TxPad= 1<<14, /* pad short frames */ + TxTC= 1<<10, /* transmit CRC */ + TxeDEF= 1<<9, + TxeHB= 1<<8, + TxeLC= 1<<7, + TxeRL= 1<<6, + TxeUN= 1<<1, + TxeCSL= 1<<0, + + /* scce */ + RXB= 1<<0, + TXB= 1<<1, + BSY= 1<<2, + RXF= 1<<3, + TXE= 1<<4, + + /* gsmrl */ + ENR= 1<<5, + ENT= 1<<4, + + /* port A */ + RXD1= SIBIT(15), + TXD1= SIBIT(14), + + /* port B */ + RTS1= IBIT(19), + + /* port C */ + CTS1= SIBIT(11), + CD1= SIBIT(10), +}; + +typedef struct Etherparam Etherparam; +struct Etherparam { + SCCparam; + ulong c_pres; /* preset CRC */ + ulong c_mask; /* constant mask for CRC */ + ulong crcec; /* CRC error counter */ + ulong alec; /* alighnment error counter */ + ulong disfc; /* discard frame counter */ + ushort pads; /* short frame PAD characters */ + ushort ret_lim; /* retry limit threshold */ + ushort ret_cnt; /* retry limit counter */ + ushort mflr; /* maximum frame length reg */ + ushort minflr; /* minimum frame length reg */ + ushort maxd1; /* maximum DMA1 length reg */ + ushort maxd2; /* maximum DMA2 length reg */ + ushort maxd; /* rx max DMA */ + ushort dma_cnt; /* rx dma counter */ + ushort max_b; /* max bd byte count */ + ushort gaddr[4]; /* group address filter */ + ulong tbuf0_data0; /* save area 0 - current frm */ + ulong tbuf0_data1; /* save area 1 - current frm */ + ulong tbuf0_rba0; + ulong tbuf0_crc; + ushort tbuf0_bcnt; + ushort paddr[3]; /* physical address LSB to MSB increasing */ + ushort p_per; /* persistence */ + ushort rfbd_ptr; /* rx first bd pointer */ + ushort tfbd_ptr; /* tx first bd pointer */ + ushort tlbd_ptr; /* tx last bd pointer */ + ulong tbuf1_data0; /* save area 0 - next frame */ + ulong tbuf1_data1; /* save area 1 - next frame */ + ulong tbuf1_rba0; + ulong tbuf1_crc; + ushort tbuf1_bcnt; + ushort tx_len; /* tx frame length counter */ + ushort iaddr[4]; /* individual address filter*/ + ushort boff_cnt; /* back-off counter */ + ushort taddr[3]; /* temp address */ +}; + +typedef struct { + SCC* scc; + int port; + int cpm; + + BD* rdr; /* receive descriptor ring */ + void* rrb; /* receive ring buffers */ + int rdrx; /* index into rdr */ + + BD* tdr; /* transmit descriptor ring */ + void* trb; /* transmit ring buffers */ + int tdrx; /* index into tdr */ +} Mot; +static Mot mot[MaxEther]; + +static int sccid[] = {-1, SCC1ID, SCC2ID, SCC3ID, SCC4ID}; +static int sccparam[] = {-1, SCC1P, SCC2P, SCC3P, SCC4P}; +static int sccreg[] = {-1, 0xA00, 0xA20, 0xA40, 0xA60}; +static int sccirq[] = {-1, 0x1E, 0x1D, 0x1C, 0x1B}; + +static void +attach(Ctlr *ctlr) +{ + mot[ctlr->ctlrno].scc->gsmrl |= ENR|ENT; + eieio(); +} + +static void +transmit(Ctlr *ctlr) +{ + int len; + Mot *motp; + Block *b; + BD *tdre; + + motp = &mot[ctlr->ctlrno]; + while(((tdre = &motp->tdr[motp->tdrx])->status & BDReady) == 0){ + b = qget(ctlr->oq); + if(b == 0) + break; + + /* + * Copy the packet to the transmit buffer. + */ + len = BLEN(b); + memmove(KADDR(tdre->addr), b->rp, len); + + /* + * Give ownership of the descriptor to the chip, increment the + * software ring descriptor pointer and tell the chip to poll. + */ + tdre->length = len; + eieio(); + tdre->status = (tdre->status & BDWrap) | BDReady|TxPad|BDInt|BDLast|TxTC; + eieio(); + motp->scc->todr = 1<<15; /* transmit now */ + eieio(); + motp->tdrx = NEXT(motp->tdrx, Ntdre); + + freeb(b); + + } +} + +static void +interrupt(Ureg*, void *ap) +{ + int len, events, status; + Mot *motp; + BD *rdre; + Block *b; + Ctlr *ctlr; + + ctlr = ap; + motp = &mot[ctlr->ctlrno]; + + /* + * Acknowledge all interrupts and whine about those that shouldn't + * happen. + */ + events = motp->scc->scce; + eieio(); + motp->scc->scce = events; + eieio(); + if(events & (TXE|BSY|RXB)) + print("ETHER.SCC#%d: scce = 0x%uX\n", ctlr->ctlrno, events); + //print(" %ux|", events); + /* + * Receiver interrupt: run round the descriptor ring logging + * errors and passing valid receive data up to the higher levels + * until we encounter a descriptor still owned by the chip. + */ + if(events & (RXF|RXB) || 1){ + rdre = &motp->rdr[motp->rdrx]; + while(((status = rdre->status) & BDEmpty) == 0){ + if(status & RxError || (status & (BDFirst|BDLast)) != (BDFirst|BDLast)){ + //if(status & RxBuff) + // ctlr->buffs++; + if(status & (1<<2)) + ctlr->crcs++; + if(status & (1<<1)) + ctlr->overflows++; + //print("eth rx: %ux\n", status); + if(status & RxError) + print("~"); + else if((status & BDLast) == 0) + print("@"); + } + else{ + /* + * We have a packet. Read it into the next + * free ring buffer, if any. + */ + len = rdre->length-4; + if((b = iallocb(len)) != 0){ + memmove(b->wp, KADDR(rdre->addr), len); + b->wp += len; + etheriq(ctlr, b, 1); + } + } + + /* + * Finished with this descriptor, reinitialise it, + * give it back to the chip, then on to the next... + */ + rdre->length = 0; + rdre->status = (rdre->status & BDWrap) | BDEmpty | BDInt; + eieio(); + + motp->rdrx = NEXT(motp->rdrx, Nrdre); + rdre = &motp->rdr[motp->rdrx]; + } + } + + /* + * Transmitter interrupt: handle anything queued for a free descriptor. + */ + if(events & TXB) + transmit(ctlr); + if(events & TXE) + cpmop(RestartTx, motp->cpm, 0); +} + +static void +ringinit(Mot* motp) +{ + int i, x; + + /* + * Initialise the receive and transmit buffer rings. The ring + * entries must be aligned on 16-byte boundaries. + */ + if(motp->rdr == 0) + motp->rdr = bdalloc(Nrdre); + if(motp->rrb == 0) + motp->rrb = ialloc(Nrdre*Bufsize, 0); + x = PADDR(motp->rrb); + for(i = 0; i < Nrdre; i++){ + motp->rdr[i].length = 0; + motp->rdr[i].addr = x; + motp->rdr[i].status = BDEmpty|BDInt; + x += Bufsize; + } + motp->rdr[i-1].status |= BDWrap; + motp->rdrx = 0; + + if(motp->tdr == 0) + motp->tdr = bdalloc(Ntdre); + if(motp->trb == 0) + motp->trb = ialloc(Ntdre*Bufsize, 0); + x = PADDR(motp->trb); + for(i = 0; i < Ntdre; i++){ + motp->tdr[i].addr = x; + motp->tdr[i].length = 0; + motp->tdr[i].status = TxPad|BDInt|BDLast|TxTC; + x += Bufsize; + } + motp->tdr[i-1].status |= BDWrap; + motp->tdrx = 0; +} + +/* + * This follows the MPC823 user guide: section16.9.23.7's initialisation sequence, + * except that it sets the right bits for the MPC823ADS board when SCC2 is used, + * and those for the 860/821 development board for SCC1. + */ +static void +sccsetup(Mot *ctlr, SCC *scc, uchar *ea) +{ + int i, rcs, tcs, w; + Etherparam *p; + IMM *io; + + + i = 2*(ctlr->port-1); + io = ioplock(); + w = (TXD1|RXD1)<<i; /* TXDn and RXDn in port A */ + io->papar |= w; /* enable TXDn and RXDn pins */ + io->padir &= ~w; + io->paodr &= ~w; /* not open drain */ + + w = (CD1|CTS1)<<i; /* CLSN and RENA: CDn and CTSn in port C */ + io->pcpar &= ~w; /* enable CLSN (CTSn) and RENA (CDn) */ + io->pcdir &= ~w; + io->pcso |= w; + iopunlock(); + + /* clocks and transceiver control: details depend on the board's wiring */ + archetherenable(ctlr->cpm, &rcs, &tcs); + + sccnmsi(ctlr->port, rcs, tcs); /* connect the clocks */ + + p = (Etherparam*)KADDR(sccparam[ctlr->port]); + memset(p, 0, sizeof(*p)); + p->rfcr = 0x18; + p->tfcr = 0x18; + p->mrblr = Bufsize; + p->rbase = PADDR(ctlr->rdr); + p->tbase = PADDR(ctlr->tdr); + + cpmop(InitRxTx, ctlr->cpm, 0); + + p->c_pres = ~0; + p->c_mask = 0xDEBB20E3; + p->crcec = 0; + p->alec = 0; + p->disfc = 0; + p->pads = 0x8888; + p->ret_lim = 0xF; + p->mflr = Rbsize; + p->minflr = ETHERMINTU+4; + p->maxd1 = Bufsize; + p->maxd2 = Bufsize; + p->p_per = 0; /* only moderate aggression */ + + for(i=0; i<Eaddrlen; i+=2) + p->paddr[2-i/2] = (ea[i+1]<<8)|ea[i]; /* it's not the obvious byte order */ + + scc->psmr = (2<<10)|(5<<1); /* 32-bit CRC, ignore 22 bits before SFD */ + scc->dsr = 0xd555; + scc->gsmrh = 0; /* normal operation */ + scc->gsmrl = (1<<28)|(4<<21)|(1<<19)|0xC; /* transmit clock invert, 48 bit preamble, repetitive 10 preamble, ethernet */ + eieio(); + scc->scce = ~0; /* clear all events */ + eieio(); + scc->sccm = TXE | RXF | TXB; /* enable interrupts */ + eieio(); + + io = ioplock(); + w = RTS1<<(ctlr->port-1); /* enable TENA pin (RTSn) */ + io->pbpar |= w; + io->pbdir |= w; + iopunlock(); + + /* gsmrl enable is deferred until attach */ +} + +/* + * Prepare the SCCx ethernet for booting. + */ +int +sccethreset(Ctlr* ctlr) +{ + uchar ea[Eaddrlen]; + Mot *motp; + SCC *scc; + char line[50], def[50]; + + /* + * Since there's no EPROM, insist that the configuration entry + * (see conf.c and flash.c) holds the Ethernet address. + */ + memset(ea, 0, Eaddrlen); + if(memcmp(ea, ctlr->card.ea, Eaddrlen) == 0){ + print("no preset Ether address\n"); + for(;;){ + strcpy(def, "00108bf12900"); /* valid MAC address to be used only for initial configuration */ + if(getstr("ether MAC address", line, sizeof(line), def) < 0) + return -1; + if(parseether(ctlr->card.ea, line) >= 0 || ctlr->card.ea[0] == 0xFF) + break; + print("invalid MAC address\n"); + } + } + + scc = IOREGS(sccreg[ctlr->card.port], SCC); + ctlr->card.irq = VectorCPIC+sccirq[ctlr->card.port]; + + motp = &mot[ctlr->ctlrno]; + motp->scc = scc; + motp->port = ctlr->card.port; + motp->cpm = sccid[ctlr->card.port]; + + ringinit(motp); + + sccsetup(motp, scc, ctlr->card.ea); + + /* enable is deferred until attach */ + + ctlr->card.reset = sccethreset; + ctlr->card.attach = attach; + ctlr->card.transmit = transmit; + ctlr->card.intr = interrupt; + + return 0; +} diff --git a/os/boot/rpcg/fblt.c b/os/boot/rpcg/fblt.c new file mode 100644 index 00000000..5014e35c --- /dev/null +++ b/os/boot/rpcg/fblt.c @@ -0,0 +1,531 @@ +#include <u.h> +#include <libc.h> +#include <libg.h> +#include <gnot.h> + +/* + * bitblt operates a 'word' at a time. + * WBITS is the number of bits in a word + * LWBITS=log2(WBITS), + * W2L is the number of words in a long + * WMASK has bits set for the low order word of a long + * WType is a pointer to a word + */ +#ifndef WBITS +#define WBITS 32 +#define LWBITS 5 +#define W2L 1 +#define WMASK ~0UL +typedef ulong *WType; +#endif + +#define DEBUG + +#ifdef TEST +/* + * globals used for testing + */ +int FORCEFORW; +int FORCEBAKW; +GBitmap *curdm, *cursm; +Point curpt; +Rectangle curr; +Fcode curf; +void *mem; +#endif + +static void +gbitexplode(ulong sw, ulong *buf, int sdep, int x) +{ + int j, o, q, n, nw, inc, qinc; + ulong s, dw, pix; + + inc = 1 << sdep; + pix = (1 << inc) - 1; + nw = 1 << x; + n = 32 >> x; + qinc = (nw << sdep) - inc; + for(o = 32 - n; o >= 0; o -= n){ + dw = 0; + s = sw >> o; + q = 0; + for(j = 0; j < n; j += inc){ + dw |= (s & (pix << j)) << q; + q += qinc; + } + for(j = 0; j < x; j++) + dw |= dw << (inc << j); + *buf++ = dw; + } +} + +/* +void +main(void) +{ + ulong buf[128]; + + gbitexplode(0x7777, buf, 0, 3); + exits(0); +} +*/ + +void +gbitblt(GBitmap *dm, Point pt, GBitmap *sm, Rectangle r, Fcode fcode) +{ + int width; /* width in bits of dst */ + int wwidth; /* floor width in words */ + int height; /* height in pixels minus 1 */ + int sdep; /* src ldepth */ + int ddep; /* dst ldepth */ + int deltadep; /* diff between ldepths */ + int sspan; /* words between scanlines in src */ + int dspan; /* words between scanlines in dst */ + int soff; /* bit offset of src start point */ + int sdest; /* bit offset of src start point that matches doff when expanded */ + int doff; /* bit offset of dst start point */ + int delta; /* amount to shift src by */ + int sign; /* of delta */ + ulong *saddr; + ulong *daddr; + ulong *s; + ulong *d; + ulong mask; + ulong tmp; /* temp storage source word */ + ulong sw; /* source word constructed */ + ulong dw; /* dest word fetched */ + ulong lmask; /* affected pixels in leftmost dst word */ + ulong rmask; /* affected pixels in rightmost dst word */ + int i; + int j; + ulong buf[32]; /* for expanding a source */ + ulong *p; /* pointer into buf */ + int spare; /* number of words already converted */ + + +#ifdef TEST + curdm = dm; + cursm = sm; + curpt = pt; + curr = r; + curf = fcode; +#endif + + gbitbltclip(&dm); + + width = r.max.x - r.min.x; + if(width <= 0) + return; + height = r.max.y - r.min.y - 1; + if(height < 0) + return; + + ddep = dm->ldepth; + pt.x <<= ddep; + width <<= ddep; + + sdep = sm->ldepth; + r.min.x <<= sdep; + r.max.x <<= sdep; + + dspan = dm->width * W2L; + sspan = sm->width * W2L; + + daddr = (ulong*)((WType)dm->base + + dm->zero*W2L + pt.y*dspan + + (pt.x >> LWBITS)); + saddr = (ulong*)((WType)sm->base + + sm->zero*W2L + r.min.y*sspan + + (r.min.x >> LWBITS)); + + doff = pt.x & (WBITS - 1); + lmask = WMASK >> doff; + rmask = (WMASK << (WBITS - ((doff+width) & (WBITS-1))))&WMASK; + if(!rmask) + rmask = WMASK; + soff = r.min.x & (WBITS-1); + wwidth = ((pt.x+width-1)>>LWBITS) - (pt.x>>LWBITS); + + if(sm == dm){ +#ifdef TEST + if(!FORCEBAKW && + (FORCEFORW || sm != dm || saddr > daddr || + (saddr == daddr && soff > doff))) + ; + else{ + daddr += height * dspan; + saddr += height * sspan; + sspan -= 2 * W2L * sm->width; + dspan -= 2 * W2L * dm->width; + } +#else + if(r.min.y < pt.y){ /* bottom to top */ + daddr += height * dspan; + saddr += height * sspan; + sspan -= 2 * W2L * sm->width; + dspan -= 2 * W2L * dm->width; + }else if(r.min.y == pt.y && r.min.x < pt.x) + abort()/*goto right*/; +#endif + } + if(wwidth == 0) /* collapse masks for narrow cases */ + lmask &= rmask; + fcode &= F; + + deltadep = ddep - sdep; + sdest = doff >> deltadep; + delta = soff - sdest; + sign = 0; + if(delta < 0){ + sign = 1; + delta = -delta; + } + + p = 0; + for(j = 0; j <= height; j++){ + d = daddr; + s = saddr; + mask = lmask; + tmp = 0; + if(!sign) + tmp = *s++; + spare = 0; + for(i = wwidth; i >= 0; i--){ + if(spare) + sw = *p++; + else{ + if(sign){ + sw = tmp << (WBITS-delta); + tmp = *s++; + sw |= tmp >> delta; + }else{ + sw = tmp << delta; + tmp = *s++; + if(delta) + sw |= tmp >> (WBITS-delta); + } + spare = 1 << deltadep; + if(deltadep >= 1){ + gbitexplode(sw, buf, sdep, deltadep); + p = buf; + sw = *p++; + } + } + + dw = *d; + switch(fcode){ /* ltor bit aligned */ + case Zero: *d = dw & ~mask; break; + case DnorS: *d = dw ^ ((~sw | dw) & mask); break; + case DandnotS: *d = dw ^ ((sw & dw) & mask); break; + case notS: *d = dw ^ ((~sw ^ dw) & mask); break; + case notDandS: *d = dw ^ ((sw | dw) & mask); break; + case notD: *d = dw ^ mask; break; + case DxorS: *d = dw ^ (sw & mask); break; + case DnandS: *d = dw ^ ((sw | ~dw) & mask); break; + case DandS: *d = dw ^ ((~sw & dw) & mask); break; + case DxnorS: *d = dw ^ (~sw & mask); break; + case D: break; + case DornotS: *d = dw | (~sw & mask); break; + case S: *d = dw ^ ((sw ^ dw) & mask); break; + case notDorS: *d = dw ^ (~(sw & dw) & mask); break; + case DorS: *d = dw | (sw & mask); break; + case F: *d = dw | mask; break; + } + d++; + + mask = WMASK; + if(i == 1) + mask = rmask; + spare--; + } + saddr += sspan; + daddr += dspan; + } +} + +#ifdef TEST +void prprog(void); +GBitmap *bb1, *bb2; +ulong *src, *dst, *xdst, *xans; +int swds, dwds; +long ticks; +int timeit; + +long +func(int f, long s, int sld, long d, int dld) +{ + long a; + int sh, i, db, sb; + + db = 1 << dld; + sb = 1 << sld; + sh = db - sb; + if(sh > 0) { + a = s; + for(i = sb; i<db; i += sb){ + a <<= sb; + s |= a; + } + } else if(sh < 0) + s >>= -sh; + + switch(f){ + case Zero: d = 0; break; + case DnorS: d = ~(d|s); break; + case DandnotS: d = d & ~s; break; + case notS: d = ~s; break; + case notDandS: d = ~d & s; break; + case notD: d = ~d; break; + case DxorS: d = d ^ s; break; + case DnandS: d = ~(d&s); break; + case DandS: d = d & s; break; + case DxnorS: d = ~(d^s); break; + case S: d = s; break; + case DornotS: d = d | ~s; break; + case D: d = d; break; + case notDorS: d = ~d | s; break; + case DorS: d = d | s; break; + case F: d = ~0; break; + } + + d &= ((1<<db)-1); + return d; +} + +void +run(int fr, int to, int w, int op) +{ + int i, j, f, t, fy, ty; + extern long *_clock; + + fr += bb2->r.min.x; + to += bb1->r.min.x; + fy = bb2->r.min.y + 1; + ty = bb1->r.min.y + 1; + if(timeit) { + memcpy(dst, xdst, dwds * sizeof(long)); + ticks -= *_clock; + gbitblt(bb1, Pt(to,ty), bb2, Rect(fr,fy,fr+w,fy+2), op); + ticks += *_clock; + return; + } + f = fr; + t = to; + memcpy(dst, xdst, dwds * sizeof(long)); + for(i=0; i<w; i++) { + gbitblt(bb1, Pt(t,ty), bb2, Rect(f,fy,f+1,fy+1), op); + gbitblt(bb1, Pt(t,ty+1), bb2, Rect(f,fy+1,f+1,fy+2), op); + f++; + t++; + } + memcpy(xans, dst, dwds * sizeof(long)); + + memcpy(dst, xdst, dwds * sizeof(long)); + gbitblt(bb1, Pt(to,ty), bb2, Rect(fr,fy,fr+w,fy+2), op); + + if(memcmp(xans, dst, dwds * sizeof(long))) { + /* + * print src and dst row offset, width in bits, and forw/back + * then print for each of the four rows: the source (s), + * the dest (d), the good value of the answer (g), + * and the actual bad value of the answer (b) + */ + print("fr=%d to=%d w=%d fb=%d%d\n", + fr, to, w, FORCEFORW, FORCEBAKW); + print("dst bitmap b %#lux, z %d, w %d, ld %d, r [%d,%d][%d,%d]\n", + bb1->base, bb1->zero, bb1->width, bb1->ldepth, + bb1->r.min.x, bb1->r.min.y, bb1->r.max.x, bb1->r.max.y); + print("src bitmap b %#lux, z %d, w %d, ld %d, r [%d,%d][%d,%d]\n", + bb2->base, bb2->zero, bb2->width, bb2->ldepth, + bb2->r.min.x, bb2->r.min.y, bb2->r.max.x, bb2->r.max.y); + for(j=0; 7*j < dwds; j++) { + print("\ns"); + for(i=0; i<7 && 7*j+i < dwds; i++) + print(" %.8lux", src[7*j + i]); + print("\nd"); + for(i=0; i<7 && 7*j+i < dwds; i++) + print(" %.8lux", xdst[7*j + i]); + print("\ng"); + for(i=0; i<7 && 7*j+i < dwds; i++) + print(" %.8lux", xans[7*j + i]); + print("\nb"); + for(i=0; i<7 && 7*j+i < dwds; i++) + print(" %.8lux", dst[7*j + i]); + print("\n"); + } + prprog(); + } +} + +void +prprog(void) +{ + exits(0); +} + +int +main(int argc, char *argv[]) +{ + int f, t, w, i, sld, dld, op, iters, simple; + ulong s, d, spix, dpix, apix, fpix, m, *ps, *pd; + Point sorg, dorg; + GBitmap *bs, *bd; + long seed; + char *ct; + + sld = 0; + dld = 0; + timeit = 0; + iters = 200; + simple = 0; + ARGBEGIN { + case 'i': + iters = atoi(ARGF()); + break; + case 's': + simple = 1; + break; + case 't': + timeit = 1; + ct = ARGF(); + if(ct) + iters = atoi(ct); + break; + } ARGEND + if(argc > 0) + sld = atoi(argv[0]); + if(argc > 1) + dld = atoi(argv[1]); + if(!timeit && !simple) { + seed = time(0); + print("seed %lux\n", seed); srand(seed); /**/ + } + + print("sld %d dld %d\n", sld, dld); + op = 1; + + /* bitmaps for 1-bit tests */ + bd = gballoc(Rect(0,0,32,1), dld); + bs = gballoc(Rect(0,0,32,1), sld); + for(i=0; i<bs->width; i++) + bs->base[i] = lrand(); + + /* bitmaps for rect tests */ + if(simple) { + dorg = Pt(0,0); + sorg = Pt(0,0); + } else { + dorg = Pt(nrand(63)-31,nrand(63)-31); + sorg = Pt(nrand(63)-31,nrand(63)-31); + } + bb1 = gballoc(Rpt(dorg,add(dorg,Pt(200,4))), dld); + bb2 = gballoc(Rpt(sorg,add(sorg,Pt(200,4))), sld); + dwds = bb1->width * Dy(bb1->r); + swds = bb2->width * Dy(bb2->r); + dst = bb1->base; + src = bb2->base; + xdst = malloc(dwds * sizeof(long)); + xans = malloc(dwds * sizeof(long)); + for(i=0; i<swds; i++) + src[i] = lrand(); + for(i=0; i<dwds; i++) + xdst[i] = lrand(); + +loop: + print("Op %d\n", op); + if(!timeit) { + print("one pixel\n"); + ps = bs->base; + pd = bd->base; + FORCEFORW = 1; + FORCEBAKW = 0; + for(i=0; i<1000; i++, FORCEFORW = !FORCEFORW, FORCEBAKW = !FORCEBAKW) { + f = nrand(32 >> sld); + t = nrand(32 >> dld); + s = lrand(); + d = lrand(); + ps[0] = s; + pd[0] = d; +#ifdef T386 + spix = (byterev(s) >> (32 - ((f+1)<<sld))) & ((1 << (1<<sld)) - 1); + dpix = (byterev(d) >> (32 - ((t+1)<<dld))) & ((1 << (1<<dld)) - 1); +#else + spix = (s >> (32 - ((f+1)<<sld))) & ((1 << (1<<sld)) - 1); + dpix = (d >> (32 - ((t+1)<<dld))) & ((1 << (1<<dld)) - 1); +#endif +#ifdef T386 + apix = byterev(func(op, spix, sld, dpix, dld) << (32 - ((t+1)<<dld))); +#else + apix = func(op, spix, sld, dpix, dld) << (32 - ((t+1)<<dld)); +#endif + gbitblt(bd, Pt(t,0), bs, Rect(f,0,f+1,1), op); + if(ps[0] != s) { + print("bb src %.8lux %.8lux %d %d\n", ps[0], s, f, t); + exits("error"); + } + m = ((1 << (1<<dld)) - 1) << (32 - ((t+1)<<dld)); +#ifdef T386 + m = byterev(m); +#endif + if((pd[0] & ~m) != (d & ~m)) { + print("bb dst1 %.8lux %.8lux\n", + s, d); + print("bb %.8lux %.8lux %d %d\n", + ps[0], pd[0], f, t); + prprog(); + exits("error"); + } + if((pd[0] & m) != apix) { + spix <<= 32 - ((f+1)<<sld); + dpix <<= 32 - ((t+1)<<dld); +#ifdef T386 + spix = byterev(spix); + dpix = byterev(dpix); +#endif + print("bb dst2 %.8lux %.8lux\n", + s, d); + print("bb %.8lux %.8lux %d %d\n", + ps[0], pd[0], f, t); + print("bb %.8lux %.8lux %.8lux %.8lux\n", + spix, dpix, apix, pd[0] & m); + prprog(); + exits("error"); + } + } + } + + print("for\n"); + FORCEFORW = 1; + FORCEBAKW = 0; + + for(i=0; i<iters; i++) { + f = nrand(64); + t = nrand(64); + w = nrand(130); + run(f, t, w, op); + } + + if(sld == dld) { + print("bak\n"); + FORCEFORW = 0; + FORCEBAKW = 1; + + for(i=0; i<iters; i++) { + f = nrand(64); + t = nrand(64); + w = nrand(130); + run(f, t, w, op); + } + } + + if(op < F) { + op++; + goto loop; + } + if(timeit) + print("time: %d ticks\n", ticks); + exits(0); +} + + +#endif diff --git a/os/boot/rpcg/flash.c b/os/boot/rpcg/flash.c new file mode 100644 index 00000000..d05f638f --- /dev/null +++ b/os/boot/rpcg/flash.c @@ -0,0 +1,212 @@ +#include "boot.h" + +typedef struct Flashdev Flashdev; +struct Flashdev { + uchar* base; + int size; + uchar* exec; + char* config; + int conflen; +}; + +enum { + FLASHSEG = 256*1024, + CONFIGLIM = FLASHSEG, + BOOTOFF = FLASHSEG, + BOOTLEN = 3*FLASHSEG, /* third segment might be filsys */ + /* rest of flash is free */ +}; + +static Flashdev flash; + +/* + * configuration data is written between the bootstrap and + * the end of region 0. the region ends with allocation descriptors + * of the following form: + * + * byte order is big endian + * + * the last valid region found that starts with the string "#plan9.ini\n" is plan9.ini + */ +typedef struct Flalloc Flalloc; +struct Flalloc { + ulong check; /* checksum of data, or ~0 */ + ulong base; /* base of region; ~0 if unallocated, 0 if deleted */ + uchar len[3]; + uchar tag; /* see below */ + uchar sig[4]; +}; + +enum { + /* tags */ + Tdead= 0, + Tboot= 0x01, /* space reserved for boot */ + Tconf= 0x02, /* configuration data */ + Tnone= 0xFF, + + Noval= ~0, +}; + +static char flashsig[] = {0xF1, 0xA5, 0x5A, 0x1F}; +static char conftag[] = "#plan9.ini\n"; + +static ulong +checksum(uchar* p, int n) +{ + ulong s; + + for(s=0; --n >= 0;) + s += *p++; + return s; +} + +static int +validptr(Flalloc *ap, uchar *p) +{ + return p > (uchar*)&end && p < (uchar*)ap; +} + +static int +flashcheck(Flalloc *ap, char **val, int *len) +{ + uchar *base; + int n; + + if(ap->base == Noval || ap->base >= FLASHSEG || ap->tag == Tnone) + return 0; + base = flash.base+ap->base; + if(!validptr(ap, base)) + return 0; + n = (((ap->len[0]<<8)|ap->len[1])<<8)|ap->len[2]; + if(n == 0xFFFFFF) + n = 0; + if(n < 0) + return 0; + if(n > 0 && !validptr(ap, base+n-1)) + return 0; + if(ap->check != Noval && checksum(base, n) != ap->check){ + print("flash: bad checksum\n"); + return 0; + } + *val = (char*)base; + *len = n; + return 1; +} + +int +flashinit(void) +{ + int len; + char *val; + Flalloc *ap; + void *addr; + long mbytes; + char type[20]; + + flash.base = 0; + flash.exec = 0; + flash.size = 0; + if(archflashreset(type, &addr, &mbytes) < 0){ + print("flash: flash not present or not enabled\n"); /* shouldn't happen */ + return 0; + } + flash.size = mbytes; + flash.base = addr; + flash.exec = flash.base + BOOTOFF; + flash.config = nil; + flash.conflen = 0; + + for(ap = (Flalloc*)(flash.base+CONFIGLIM)-1; memcmp(ap->sig, flashsig, 4) == 0; ap--){ + if(0) + print("conf #%8.8lux: #%x #%6.6lux\n", ap, ap->tag, ap->base); + if(ap->tag == Tconf && + flashcheck(ap, &val, &len) && + len >= sizeof(conftag)-1 && + memcmp(val, conftag, sizeof(conftag)-1) == 0){ + flash.config = val; + flash.conflen = len; + if(0) + print("flash: found config %8.8lux(%d):\n%s\n", val, len, val); + } + } + if(flash.config == nil) + print("flash: no config\n"); + else + print("flash config %8.8lux(%d):\n%s\n", flash.config, flash.conflen, flash.config); + if(issqueezed(flash.exec) == Q_MAGIC){ + print("flash: squeezed powerpc kernel installed\n"); + return 1<<0; + } + if(GLLONG(flash.exec) == Q_MAGIC){ + print("flash: unsqueezed powerpc kernel installed\n"); + return 1<<0; + } + flash.exec = 0; + print("flash: no powerpc kernel in Flash\n"); + return 0; +} + +char* +flashconfig(int) +{ + return flash.config; +} + +int +flashbootable(int) +{ + return flash.exec != nil && (issqueezed(flash.exec) || GLLONG(flash.exec) == Q_MAGIC); +} + +int +flashboot(int) +{ + ulong entry, addr; + void (*b)(void); + Exec *ep; + Block in; + long n; + uchar *p; + + if(flash.exec == 0) + return -1; + p = flash.exec; + if(GLLONG(p) == Q_MAGIC){ + /* unsqueezed: copy data and perhaps text, then jump to it */ + ep = (Exec*)p; + entry = PADDR(GLLONG(ep->entry)); + p += sizeof(Exec); + addr = entry; + n = GLLONG(ep->text); + if(addr != (ulong)p){ + memmove((void*)addr, p, n); + print("text: %8.8lux <- %8.8lux [%ld]\n", addr, p, n); + } + p += n; + if(entry >= FLASHMEM) + addr = 3*BY2PG; /* kernel text is in Flash, data in RAM */ + else + addr = PGROUND(addr+n); + n = GLLONG(ep->data); + memmove((void*)addr, p, n); + print("data: %8.8lux <- %8.8lux [%ld]\n", addr, p, n); + }else{ + in.data = p; + in.rp = in.data; + in.lim = p+BOOTLEN; + in.wp = in.lim; + n = unsqueezef(&in, &entry); + if(n < 0) + return -1; + } + print("entry=0x%lux\n", entry); + uartwait(); + scc2stop(); + /* + * Go to new code. It's up to the program to get its PC relocated to + * the right place. + */ + b = (void (*)(void))KADDR(PADDR(entry)); + (*b)(); + return -1; +} diff --git a/os/boot/rpcg/fns.h b/os/boot/rpcg/fns.h new file mode 100644 index 00000000..fe747180 --- /dev/null +++ b/os/boot/rpcg/fns.h @@ -0,0 +1,118 @@ +Alarm* alarm(int, void (*)(Alarm*), void*); +void alarminit(void); +void archbacklight(int); +char* archconfig(void); +void archdisableuart(int); +void archenableuart(int, int); +void archenableusb(int); +void archetherdisable(int); +int archetherenable(int, int*, int*); +int archflashreset(char*, void**, long*); +void archinit(void); +int archoptionsw(void); +int bootp(int, char*); +void cancel(Alarm*); +void checkalarms(void); +void clockinit(void); +void clockintr(Ureg*, void*); +void consinit(void); +void cpminit(void); +void cpuidprint(void); +#define dcflush(a,b) +void delay(int); +void eieio(void); +uchar* etheraddr(int); +int etherinit(void); +int etherrxpkt(int, Etherpkt*, int); +int ethertxpkt(int, Etherpkt*, int, int); +void exception(void); +int flashboot(int); +int flashbootable(int); +char* flashconfig(int); +int flashinit(void); +void free(void*); +void freeb(Block*); +int getcfields(char*, char**, int, char*); +char* getconf(char*); +ulong getdec(void); +ulong gethid0(void); +ulong getimmr(void); +ulong getmsr(void); +ulong getpvr(void); +int getstr(char*, char*, int, char*); +ulong gettbl(void); +ulong gettbu(void); +int hardinit(void); +long hardread(int, void*, long); +long hardseek(int, long); +long hardwrite(int, void*, long); +long i2crecv(int, void*, long); +long i2csend(int, void*, long); +void i2csetup(void); +void* ialloc(ulong, int); +Block* iallocb(int); +void idle(void); +int isaconfig(char*, int, ISAConf*); +int issqueezed(uchar*); +void kbdchar(Queue*, int); +void kbdinit(void); +void kbdreset(void); +void machinit(void); +void* malloc(ulong); +ulong mapalloc(RMap*, ulong, int, int); +void mapfree(RMap*, ulong, int); +void mapinit(RMap*, Map*, int); +void meminit(void); +void microdelay(int); +void mmuinit(void); +int optionsw(void); +void panic(char*, ...); +int parseether(uchar*, char*); +int plan9boot(int, long (*)(int, long), long (*)(int, void*, long)); +void putdec(ulong); +void puthid0(ulong); +void putmsr(ulong); +int qbgetc(Queue*); +void qbputc(Queue*, int); +void qbwrite(Queue*, Block*); +Block* qget(Queue*); +long qlen(Queue*); +Queue* qopen(int, int, void (*)(void*), void*); +#define qpass qbwrite +void scc2stop(void); +void sccnmsi(int, int, int); +void sched(void); +void screeninit(void); +void screenputs(char*, int); +void sdraminit(ulong); +Partition* sethardpart(int, char*); +Partition* setscsipart(int, char*); +void setvec(int, void (*)(Ureg*, void*), void*); +int splhi(void); +int spllo(void); +void splx(int); +void trapinit(void); +void uartputs(char*, int); +void uartsetboot(void (*f)(uchar*, int)); +void uartspecial(int, int, Queue**, Queue**, void(*)(Queue*,int)); +void uartwait(void); +long unsqueezef(Block*, ulong*); + +#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) ((GLSHORT(p)<<16)|GLSHORT(p+2)) + +#define KADDR(a) ((void*)((ulong)(a)|KZERO)) +#define PADDR(a) ((((ulong)(a)&KSEGM)!=KSEG0)?(ulong)(a):((ulong)(a)&~KZERO)) + +/* IBM bit field order */ +#define IBIT(b) ((ulong)1<<(31-(b))) +#define SIBIT(n) ((ushort)1<<(15-(n))) + +#define IOREGS(x, T) ((T*)((char*)m->iomem+(x))) + +int uartinit(void); +Partition* setuartpart(int, char*); +long uartread(int, void*, long); +long uartseek(int, long); diff --git a/os/boot/rpcg/g.mx b/os/boot/rpcg/g.mx new file mode 100644 index 00000000..2398c12a --- /dev/null +++ b/os/boot/rpcg/g.mx @@ -0,0 +1,1987 @@ +S0030000FC +S325000100007C6000A63C800000608480427C632078606310007C0004AC7C6001247C0004AC52 +S325000100204C00012C7C908AA63C800A007C908BA64C00012C3C800C007C908BA64C00012C0A +S325000100403C8004007C908BA64C00012C7C0004AC7C988AA63C800A007C988BA64C00012C2F +S325000100603C800C007C988BA64C00012C3C8004007C988BA64C00012C388000077C9E23A6D3 +S325000100807CBE9AA63C80FA207C9E9BA63860FF88906400043C6001016063244090640000DE +S325000100A0380000003C40001460427FF83C40001460427FF83C60FFC26063D7103882800866 +S325000100C07C0418004182002C38A2A1F87CA4285038A500037CA516707CA903A63884FFFC7B +S325000100E03863FFFC84A3000494A400044200FFF83C60FFC2606302007C6803A64E80002026 +S325000101003862A1F8388227107C8320514081001C7C8416707C8903A63863FFFC3800000065 +S32500010120940300044200FFFC3822A3C89022801438210FF8380000004800AA01480086F587 +S32500010140480000003D00FA40806800003CA008007C63287890680000480000007C6000A6CC +S325000101604E8000207C0004AC7C6001247C0004AC4C00012C4E8000207C0006AC4E800020AE +S325000101804E8000207C6000A6606480007C0004AC7C8001247C0004AC4C00012C4E800020C4 +S325000101A07C6000A65464045E7C0004AC7C8001247C0004AC4C00012C4E8000207C8000A61A +S325000101C0506404207C0004AC7C8001247C0004AC4C00012C4E8000207C6C42E64E80002062 +S325000101E07C7F42A64E8000207C7E9AA64E8000207C7602A64E8000207C7603A64E800020EE +S325000102003821FF58BC4100303C40001460427FF87C9142A69081002C7CB042A690A10028B2 +S325000102207CC902A690C100247C8102A6908100207CB342A690A1001C7CD242A690C100187C +S325000102407C9A02A6908100107CBB02A690A1000C90010008386100087C60092D3800000018 +S325000102604E800020B8410030800100287C1043A6800100247C0903A6800100207C0103A6A8 +S325000102808001001C7C0FF120800100187C1243A6800100107C1A03A68001000C7C1B03A671 +S325000102A08021002C4E8000207C3143A67C0000267C1343A67C0802A64BFFFF4938000000D6 +S325000102C04800AC294BFFFFA17C1242A67C0803A67C1042A64C00012C4C0000647FE802A6C1 +S325000102E097E1FFE84BFFFF05812280147064FFFF5484C23F418200802C0400204182006CA6 +S325000103002C040021418200587C0A0378914900143D00FA409109001C814900203CC0007AEE +S3250001032060C6120090C9000C80EA028454E7653E394700018089000C7C8451D6908900086D +S3250001034080E9001C3CC03E0090C7000083E100007FE803A6382100184E8000203D40000828 +S32500010360614A23A04BFFFFA83D400008614A23004BFFFF9C3D400008614A60004BFFFF9076 +S325000103807FE802A697E1FFE038629EC0480035D538629ED3480035CD4BFFFE49546A843E40 +S325000103A02C0A0006418101B4418201A42C0A0001418201902C0A00034182017C2C0A0004DD +S325000103C04182016838629F0891410008480035954BFFFE117066FFFF90C1001038629F1CDA +S325000103E081010010910100084800357938629F2E480035714BFFFDF5706AFFFF9141001881 +S325000104007D464671418201182C060020418201042C060021418200F038629F4F7D4846705C +S32500010420910100084800353D38629F5A80810018708400FF90810008480035294800019D1D +S325000104409061001038629F6880810010908100084800351138629F7880E2801480E7001C11 +S3250001046080E7000090E10008480034F98142801438629F87808A002080840284908100083C +S3250001048080CA002080C6028090C1000C480034D538629FA481028014810800083D20000F84 +S325000104A0612942407D084BD691010008480034B538629FB5480034AD8142801438629FB75A +S325000104C080AA002080A5010090A1000880EA002080E7010490E1000C4800348938629FD0EB +S325000104E08082801480840020A084017A908100084800347183E100007FE803A638210020A9 +S325000105004E80002038629F47480034594BFFFF1C38629F404800344D4BFFFF1038629F3523 +S32500010520480034414BFFFF0438629EE7480034354BFFFEA038629EE0480034294BFFFE9459 +S3250001054038629ED94800341D4BFFFE8838629EEE480034114BFFFE7C2C0A00074182001C87 +S325000105602C0A0050418200084BFFFE5C38629F01480033F14BFFFE5C38629EF6480033E5A7 +S325000105804BFFFE507FE802A697E1FFF03862A0A7480033D180628014806300145463C23EF5 +S325000105A070630FFF2C03082340820028386000015463103A388283C07C6322148063000080 +S325000105C083E100007FE803A6382100104E8000207C0303784BFFFFDC806280148063001CB5 +S325000105E080630000706300F05463E13E4E8000208102801480C8000038E000327FE63B96AB +S325000106007FFF39D67CDF30514082001480E8001C80C700006CC6080090C700004E8000204A +S325000106207FE802A697E1FFF080A2801480A5002080A5010070A50001408200183860FFFF96 +S3250001064083E100007FE803A6382100104E80002038E2A0C490E100084800CDA18081001802 +S325000106603CC0FFC090C4000080E1001C3C800040908700007C03037883E100007FE803A666 +S32500010680382100104E8000207FE802A697E1FFE87C030000408100183860FFFF83E100003C +S325000106A07FE803A6382100184E800020806100203882A0CE908100084800CD4180C10020CB +S325000106C0390000029106001C3862A0D2480000CD7C671B787C030000418200148061002037 +S325000106E03863002C90E10008480029053860000183E100007FE803A6382100184E800020D1 +S325000107003821FFF0814280142C030004418200103860FFFF382100104E800020812A002075 +S32500010720810A001C80E8000064E7800090E80000A0E9095260E70A00B0E90952A0E9095055 +S3250001074070E7F5FFB0E9095080A1001838E0000790E500008101001C38A0000590A80000D5 +S325000107607C030378382100104E80002080A2801480A5001C808500003FE07FFF63FFFFFF28 +S325000107807FE42039908500004E8000204E8000204E8000204E8000207FE802A697E1FFD073 +S325000107A09061003480C284247C0600004082006048008929386000A93882C3A89081000806 +S325000107C038C0008090C1000C48008F4D7C0300004180019C3C600000606380A93882C3A88F +S325000107E0388400809081000838C0008090C1000C48008F257C0300004180017438E000FF00 +S3250001080098E2C4A839000001910284243922C3A888C900002C0600FF4182001088E90000EA +S325000108202C07000A408200187C03037883E100007FE803A6382100304E80002091210028DB +S3250001084088A900002C05000A4182001088C900002C0600FF408201009121002C88C90000DE +S325000108602C06003D40820050806100344800CB5D8121002C810100287C8848507C041800BF +S3250001088040820034806100344800CB41906100188061003480A1002890A1000880E10018D9 +S325000108A090E1000C4800CAAD8121002C7C03000041820038888900002C04000A418200108F +S325000108C088A900002C0500FF40820018888900002C04000A4082FF3C392900014BFFFF34AE +S325000108E0392900014BFFFFD039490001890900002C08000A41820010888900002C0400FF0F +S325000109004082004C38628048914100089121002C914100287CCA485090C1000C4800C64520 +S3250001092038E2804880A1002C7CE53A14810100287CE83850980700003862804883E10000D7 +S325000109407FE803A6382100304E800020392900014BFFFF9C88E900002C07003D4082000816 +S325000109604BFFFEF8392900014BFFFED83862A0D548002FF17C03037883E100007FE803A6C8 +S32500010980382100304E8000203821FFF080A2801480A500087CA51BD638A500087CA5267000 +S325000109A02C051000418000183865000F7C631E7060630001382100104E80002054A3083CA7 +S325000109C0382100104E8000207FE802A697E1FFD89061002C38600009900100084BFFFDB10C +S325000109E0810280148128002080A90ABC60A500C090A90ABC9121002480A90AB83FE0FFFF7F +S32500010A0063FFFF3F7FE5283990A90AB8806100304BFFFF798121002464680001910909F076 +S32500010A2080A90AE03FE0FFFF63FF0FFF7FE5283990A90AE038600001480032B18141002C75 +S32500010A407C691B783CA0FA2060A53E8090A10020B0650000906A00B43C8000006084B000FA +S32500010A60B0830000B0030002390A00247508E0003CA020007C0828004182011038EA002401 +S32500010A8090E9000438600001480032618141002C7C691B7881010020B0680002906A00B88A +S32500010AA038C03000B0C30000B003000238AA00A474A5E0003CE020007C053800418200B8F0 +S32500010AC0388A00A4908900047C03037839000009910100089001000C48003085812100205A +S32500010AE038E0001898E9000438A0001898A9000539000001B109000638C00001B0C9002870 +S32500010B00B009002CB009002E39000001B1090030808280148084002039240A8038C000FF46 +S32500010B2098C9000691210018388000179889000A386000143CA0FFC260A50C9C90A1000854 +S32500010B4080E1002C90E1000C4800A1298121001838E04820B0E90002A0A9000260A500034A +S32500010B60B0A9000283E100007FE803A6382100284E800020388A00A43FE0FFFF63FFFFFF4D +S32500010B807FE420394BFFFF4038EA00243FE0FFFF63FFFFFF7FE738394BFFFEE87FE802A630 +S32500010BA097E1FFD08121003880A2801480A5002038A50A8038E000FF98E50006810900B4D3 +S32500010BC0910100207C0800004182001480810020A0840000708480004182009C816900B847 +S32500010BE07C0B00004182001491610020A08B0000708480004182001483E100007FE803A694 +S32500010C00382100304E8000203940FFFF80C900107C0600004182001C9121002C806900104E +S32500010C2048009409816100208121002C7C6A1B782C0AFFFF4182002C994900A438C00001DD +S32500010C40B0CB0002A08B000060848000B08B000083E100007FE803A6382100304E8000205B +S32500010C609809000883E100007FE803A6382100304E80002080A9000C7C050000418200144C +S32500010C8080810020A08400027C0400404181002481010020A0A8000060A59000B0A8000089 +S32500010CA083E100007FE803A6382100304E80002080A900187C0500004182002438690024D4 +S32500010CC080A10020A0A5000290A1000880E900187CE803A64E8000214BFFFFB89121002CF0 +S32500010CE080C900147C060000418200487C0A037881010020A10800027C0A40404080FF945C +S32500010D00914100247CCA4A1488C600248069000C90C1000880E900147CE803A64E800021F9 +S32500010D208121002C80A10024394500014BFFFFC480610020A0630002480090E9906100183D +S32500010D408063000480C1002C38C6002490C1000880810020A08400029081000C4800C2054A +S32500010D608121001881010020A1080002808900047D044214910900048061002C8063000CE7 +S32500010D80912100084800920D4BFFFF087FE802A697E1FFE09061001C4BFFF4098121001CE2 +S32500010DA090610018888900087C0400004082001C80690010480092758121001C90610014A1 +S32500010DC02C03FFFF4082001C806100184BFFF3F183E100007FE803A6382100204E800020FF +S32500010DE080C280B47C06000041820064810900B8A108000071088000418200084BFFFFF0E5 +S32500010E0080C1001498C900A480C900B838A00001B0A6000280C900B8A0A6000060A5800073 +S32500010E20B0A600007D284B7880A280B47C0500004082001038A0000198A800084BFFFF6872 +S32500010E407C05037898A800084BFFFF5C7C0A0378914100102C0A00644080FFA880C900B8BD +S32500010E60A0C6000070C68000408200084BFFFF943860000148001C098121001C80C1001093 +S32500010E80394600014BFFFFCC7FE802A697E1FFE0906100243902C4B080A800047C050000DF +S32500010EA04182001483E100007FE803A6382100204E8000209101001C38C0000190C8000476 +S32500010EC038601000900100089001000C90010010480090098121001C9069000C8101002C3A +S32500010EE09068000038604000900100083CE0FFC260E70E8C90E1000C9121001048008FDDD1 +S32500010F00814100288121001C9069001080C100309066000080A1003490A90014388000094F +S32500010F20908900007C0A000040820008394025807D234B78914100084BFFFA9183E10000AD +S32500010F407FE803A6382100204E8000209062C4C84E8000207FE802A697E1FFD88181003017 +S32500010F607C6D1B7838C2C4B090C100247C0B03787C6A1B7891A1002C7D0D62147C0A40402C +S32500010F804080002C88AA00007CA507742C05000A40820008396B0001394A000191A1002C04 +S32500010FA07D0D62147C0A40404180FFDC7C6C5A1448008E71818100308141002C7C6B1B7851 +S32500010FC07D856378398CFFFF7C0500004182005488AA00007CA507742C05000A40820018EF +S32500010FE080CB000439060001910B00043900000D99060000808B000438C4000190CB00046B +S325000110007D465378394A000188C6000098C400007D856378398CFFFF7C0500004082FFB477 +S3250001102080610024806300109161000848008F6583E100007FE803A6382100284E80002098 +S325000110403821FFF03902C4B088E800087C070000418200084BFFFFF4382100104E80002038 +S325000110607FE802A697E1FFE0812100289061002438A2C5707C0900004081001490A1001C6E +S32500011080808500007C0400004082001483E100007FE803A6382100204E8000207D234B78B0 +S325000110A048008D819061001880630004808100249081000880E1002890E1000C4800BEA5F4 +S325000110C08121001880E10028808900047CE43A1490E900048061001C8063000091210008F4 +S325000110E048008EB183E100007FE803A6382100204E800020386000014E8000207FE802A6F1 +S3250001110097E1FFF08061001838A2819890A100084800C3517C0300004182001C8061001889 +S325000111203882819D908100084800C3397C03000040820038900281F83CC0002090C281FC04 +S32500011140386281F83863000838E281A290E100084800C2A9386281F883E100007FE803A6E2 +S32500011160382100104E8000207C03037883E100007FE803A6382100104E8000207FE802A63D +S3250001118097E1FFE88082C5707C0400004082001C3C600001900100089001000C90010010E0 +S325000111A048008D399062C5708102C5747C080000418200108062C57448008CC19002C57465 +S325000111C0386281A74800279D3C60FFC2606311604BFFFD7D38C0FFFF90C2C5789002C57C8D +S325000111E09002C5C09002C5C47C03037883E100007FE803A6382100184E8000207FE802A6DA +S3250001120097E1FFD08181003890610034810100349101001C3942C57080E2801480E70000B0 +S3250001122090E1002C918100387C0C000040810140812A000491410028900A00047C0900006A +S32500011240408200A0900A0054806A000048008CC981810038814100287C691B787C03000095 +S325000112604082008080C2801480C600008101002C7CC8305054C5083C7CC62A1454C6183850 +S3250001128054A5482C7CC6285038E000327CC63B9628063A984180FFB480EA005438E7000171 +S325000112A090EA00542C07000341800020386281C1480026B17C03037883E100007FE803A6D9 +S325000112C0382100304E800020386281D039000001910100084BFFFC81814100284BFFFF6C6B +S325000112E080A9000480C900007D4628507C0A6000408100087D8A63788061001C91210020D6 +S3250001130080E9000090E10008914100249141000C4800BC5181610024814100288121002009 +S32500011320808900007CE45A1490E9000080E9000080C900047C073040418000507D234B7839 +S3250001134048008B39816100248141002880E100387D8B385080E1001C7CA75A1490A1001C06 +S32500011360918100387C0C00004181FEC88061001C80E100347C67185083E100007FE803A6BB +S32500011380382100304E800020912A00044BFFFFC07FE802A697E1FFE0808100289081001C4B +S325000113A08122C5C07C0900004081005880E1002C7C093800408100088121002C8102C5C077 +S325000113C07CC9405090C2C5C08061001C38E2C57038E7001090E10008912100189121000CDE +S325000113E04800BB81812100188081001C7CE44A1490E1001C8081002C7CE9205090E1002CA1 +S3250001140080E1002C7C070000408100C83862815038A0004090A100084BFFFDE58141002C56 +S325000114207C691B782C030040408000187C03037883E100007FE803A6382100204E80002011 +S325000114407C035000408100307C8A48509082C5C03862C5703863001038A281507CA55214E4 +S3250001146090A1000880A2C5C090A1000C4800BAF58121002C8061001C38C2815090C1000862 +S32500011480912100189121000C4800BAD9812100188101002C7CC9405090C1002C8101001C8A +S325000114A07CC84A1490C1001C80C2C57C38C6000190C2C57C386281D2388000019081000842 +S325000114C04BFFFA9580E1002C7C0700004181FF408061001C810100287C68185083E10000C4 +S325000114E07FE803A6382100204E8000203821FFE87C0B03782C0B0100408000545569C00E54 +S32500011500394000087C0A00004081002875248000418200445526083C3FE004C163FF1DB7DB +S325000115207FE93278394AFFFF7C0A00004181FFE05567103A38A2DC307CE72A1491270000A5 +S32500011540396B00012C0B01004180FFB4382100184E8000205529083C4BFFFFCC7FE802A6EE +S3250001156097E1FFF081410018906100148082DC347C0400004082000C4BFFFF758141001826 +S3250001158080C1001C3FE0FFFF63FFFFFF7FE8327881210014394AFFFF7C0A00004180003C9F +S325000115A05505463E7D264B783929000188C600007CA5327854A5103A38C2DC307CA53214B4 +S325000115C080A500005507402E7CE82A78394AFFFF7C0A00004080FFCC3FE0FFFF63FFFFFF00 +S325000115E07FE3427883E100007FE803A6382100104E800020816100088121000C7C0B0000DE +S32500011600408200148083000090890000912300004E80002080AB000090A90000912B00000F +S325000116204E800020814100088121000C7C0A00004082001080890000908300004E800020DB +S3250001164080C9000090CA00004E8000207FE802A697E1FFE87C09037838E2ED382C09000A06 +S325000116604080002C80C700047C0600004082001080A7000C7C0500004182003039290001CE +S3250001168038E700142C09000A4180FFDC386282D8480023597C03037883E100007FE803A60F +S325000116A0382100184E8000209007000C9007001038A0000190A700047CE33B7883E10000F0 +S325000116C07FE803A6382100184E8000207FE802A697E1FFD89061002C7C03000040800008D2 +S325000116E09001002C4BFFEABD906100184BFFFF61818280147C6A1B7880C1002C54C5083CA8 +S325000117007CC62A1454C620367CC62A1438E003E87CC63B9690C3000880A1003090A3000C51 +S3250001172080810034908300107C0B0378812C00187C0900004182003480A90008808A0008C4 +S325000117407C0520004181005480A90008808A00087CA5205090AA00087D2B4B7881290000A0 +S325000117607C0900004082FFD4386C001891610008914100249141000C4BFFFE7D8061001800 +S325000117804BFFEA3D8061002483E100007FE803A6382100284E800020808A00088109000845 +S325000117A07C844050908900084BFFFFC09003000C4E8000204E8000207FE802A697E1FFA8BF +S325000117C04BFFE9E1814280149061004C812A00187C090000418200A47C0B03787C09000024 +S325000117E04182001080E900087C070000408100A47C0900004182001080E9000838E7FFFFD0 +S3250001180090E900087C090378916100507C095800408000685527103A3901001C7CE7421424 +S3250001182080E7000080E7000C7C07000041820028912100545523103A38C1001C7C63321457 +S32500011840806300007CE803A64E80002181610050812100545525103A3881001C7CA522148A +S3250001186080A500009005000439290001916100507C0958004180FFA08061004C4BFFE94120 +S3250001188083E100007FE803A6382100584E8000202C0B000A418000084BFFFF589161005041 +S325000118A05568103A38C1001C7D08321491280000386A0018900100089121000C4BFFFD69C0 +S325000118C081428014812A001880E10050396700014BFFFF0CA121000A5527043E54E7C23E7B +S325000118E098E300005526043E98C300014E800020814100085544463E988300005546843E00 +S3250001190098C300015548C23E99030002994300034E8000207C671B78886300005463C00E76 +S32500011920888700015484801E7C63237888A7000254A5402E7C632B7888C700037C633378AA +S325000119404E8000207C671B78886300005463402E88A700017C632B784E8000203821FFD83C +S325000119608222809C814100307C691B787C0F03787C0C03787C0B03787C100378706500014E +S32500011980418200207C0A000041820014888900007D8C2214394AFFFF392900013A00000191 +S325000119A02C0A001041800054A0E90000A08900027D6B3A14A0C900047DAB2214A109000660 +S325000119C07DCD3214A0A900087DCE4214A0E9000A7DCE2A14A089000C7DCE3A14A0C9000E1D +S325000119E07DAE22147D6D3214394AFFF0392900102C0A00104080FFB42C0A00024180001C9D +S32500011A00A0C900007D6B3214394AFFFE392900022C0A00024080FFEC7C10000041820070A2 +S32500011A207C0A00004182000C88A900007DEF2A14889100007C8407747C0400004182004850 +S32500011A407DEF5A145588C23E7D2F4214718800FF5508402E7D2942145528843F41820014F0 +S32500011A607127FFFF7D283A145528843F4082FFF43FE0FFFF63FFFFFF7FE34A7838210028BF +S32500011A804E8000207D8C5A144BFFFFBC7C0A00004182000C88A900007D8C2A1488910000EF +S32500011AA07C8407747C0400004182000C7D8C5A144BFFFF947DEF5A144BFFFF8C3821FFF00A +S32500011AC07C691B787C0B037888E3000070E7000F54EA103A7C0A00004081002888C900006C +S32500011AE054C6402E890900017CC643787D6B3214394AFFFE392900027C0A00004181FFE08E +S32500011B007168FFFF5566843E7D0832147104FFFF5507843E7C843A146883FFFF382100106E +S32500011B204E8000207FE802A697E1FFD0906100343862B7C89061002C9001000838E005F059 +S32500011B4090E1000C4800B1E98061002C3863002A80A1003C90A10008810100409101000C57 +S32500011B604800B4018121002C80C1004039460008980900163900001199090017980900141C +S32500011B80980900153869001891410020914100084BFFFD458061002C3863001A8102822090 +S32500011BA0910100084BFFFD4D8061002C38630022A0E2822490E100084BFFFD1D8061002C14 +S32500011BC03863001E8101003881080000910100084BFFFD218061002C3863002480810038FB +S32500011BE0A0840004908100084BFFFCED8061002C3863002680E1002090E100084BFFFCD983 +S32500011C008121002C98090028980900293869001680E1004038E7001490E100084BFFFD41D0 +S32500011C205464043E908100188061002C3863002881010018910100084BFFFC9D3922B7C8B9 +S32500011C40810100403948002C390000459909000E9809000F390000FF990900169121002866 +S32500011C60386900109141002438AAFFF290A100084BFFFC6580610028386300128082801CAB +S32500011C8038E4000190E2801C908100084BFFFC49812100289809001498090015980900187C +S32500011CA0980900193869000E4BFFFE155468043E91010018806100283863001880810018DA +S32500011CC0908100084BFFFC11806100283863000C39000800910100084BFFFBFD80610028B7 +S32500011CE080C1003838C6000690C10008388000069081000C4800B26D8061003438E2B7C817 +S32500011D0090E10008808100249081000C38E0138890E100104800471583E100007FE803A6B5 +S32500011D20382100304E8000207FE802A697E1FF60906100A49801001C38A0000598A1001DC2 +S32500011D409801001E80C100AC98C1001F3861001C3863000480C100B090C100084800B69D27 +S32500011D60806100B04800B66538830005806100A4810100A89101000838C1001C90C1000CED +S32500011D80908100104BFFFDA180C100B47C0600004182001C38629C48810100AC9101000897 +S32500011DA080C100B090C1000C48001BB983E100007FE803A6382100A04E8000207FE802A648 +S32500011DC097E1FFD09061003480A281F47C0500004082029C392003E880828014808400003A +S32500011DE05485083C7C842A145484183854A5482C7C84285038C000327C8433967C89221446 +S32500011E009081001880A2801480A5000054A6083C7CA5321454A5183854C6482C7CA530509A +S32500011E2038E000327CA53B96810100187C082840408102288061003438E2BDB890E10008D1 +S32500011E4080828014808400005486083C7C8432145484183854C6482C7C84305038E00032FD +S32500011E607C843B96810100187C8440509081000C480044319061002C7C0300004181000820 +S32500011E804BFFFF843882BDB8908100203864000C4BFFFAB55466043E2C060800418200086C +S32500011EA04BFFFF64806100203863000E4BFFFC11812100207C0300004182001038629C5EC5 +S32500011EC048001AA14BFFFF4088E9000E2C0700454182001038629C6F48001A894BFFFF28A4 +S32500011EE0890900172C080011418200084BFFFF1898090016386900264BFFFA4D5466043EB6 +S32500011F00806100203863001890C1002890C100084BFFF9C580610020386300284BFFFA29FB +S32500011F207C030000408200F480A10038A0A500047C050000418200208061002038630022A1 +S32500011F404BFFFA0581010038A10800047C0340004082FEB4806100203863001A4BFFF9B9E5 +S32500011F60814100389061001C80AA00003880FFFF7C0520004182001080AA00007C0328002E +S32500011F804082FE8480C100283926FFF880C100407C0930004081001038629CA6480019C52E +S32500011FA04BFFFE648061003C808100203884002A90810008912100289121000C4800AFA5FD +S32500011FC080A1003880E1001C90E5000080610020386300224BFFF97181210038B069000446 +S32500011FE03869000638A2BDB838A5000690A1000838E0000690E1000C4800AF693880000114 +S32500012000908281F48061002883E100007FE803A6382100304E80002080610020386300168C +S32500012020808100283884000C908100084BFFF9315469043E5528043E7C0800004182FEEC2C +S3250001204038629C815527043E90E1000880E1002C90E1000C4800190D7C03037883E10000B5 +S325000120607FE803A6382100304E800020392013884BFFFD687FE802A697E1FDC89061023CB4 +S325000120809801002638E0000198E10027386100263863000238829CBB9081000880C10244B4 +S325000120A090C1000C48001879390300023861002638630001910102307C681A1438829CBE60 +S325000120C090810008480018598161024038A3000280C102307CA62A1490A10230A08B0004C1 +S325000120E0908102287C090378912102342C0900054080007081010228B10B00048061023CC1 +S325000121009161000838E1002690E1000C80810230908100104BFFFA1181210240B0090004B8 +S325000121208061023C9121000880A1024890A1000C39000204910100104BFFFC858161024047 +S32500012140812102482C0300044080003480C1023439260001912102342C0900054180FF9814 +S3250001216038629D05480017FD3860FFFF83E100007FE803A6382102384E8000208889000024 +S325000121805484402E88C900017C8433782C040003418200482C040005418200084BFFFFB0BE +S325000121A038629CC488C9000254C6402E890900037CC6437890C1000838A9000490A1000C36 +S325000121C0480017A13860FFFF83E100007FE803A6382102384E8000203960000188890002C0 +S325000121E05484402E88C900037C843378916283E87C0458004182004838629CDE9081000825 +S32500012200480017618061023C80C1024090C10008388000019081000C38C29CF990C1001036 +S32500012220900100144BFFFB053860FFFF83E100007FE803A6382102384E8000203863FFFC87 +S3250001224083E100007FE803A6382102384E8000207FE802A697E1FFD0812283E890610034F9 +S325000122609801002038800004988100217D25467098A100229921002338A9000190A283E899 +S32500012280810100403908000491010040900100248061003480E1003890E1000838A1002089 +S325000122A090A1000C38E0000490E100104BFFF8798061003480E1003890E1000880A1003CFE +S325000122C090A1000C81010040910100104BFFFAF1816100408141003C7C691B787C035800B2 +S325000122E04080006438629D2C912100089161000C480016718061003480C1003890C10008E2 +S32500012300388000029081000C38C29D4090C10010900100144BFFFA158101002438C8000102 +S3250001232090C100242C080005408000084BFFFF643860FFFF83E100007FE803A638210030E0 +S325000123404E800020890A00025508402E88AA00037D082B789101002C808283E87C082000FC +S325000123604182007C38629D4B480015F9814283E88121002C38CAFFFF7C09300040820018B4 +S3250001238080A1002439050001910100242C0500084180FF0038629D4D912100089141000CE7 +S325000123A0480015C18061003480E1003890E1000838A0000190A1000C38E29D7590E100100E +S325000123C0900100144BFFF9653860FFFF83E100007FE803A6382100304E8000203863FFFC92 +S325000123E083E100007FE803A6382100304E8000207FE802A697E1FC48906103BC48003E6981 +S32500012400814103C0906100C07C0300004082002838629D8180A103BC90A1000848001545A3 +S325000124203860FFFF83E100007FE803A6382103B84E8000209001002C900100287C0A00008D +S325000124404182001488AA00007CA507747C050000408205C03861024C9001000838A0016C03 +S3250001246090A1000C4800A8C938E0000198E1024C390000019901024D388000069881024E35 +S325000124803861024C3863001C80A100C090A10008390000069101000C4800AAC990028220B1 +S325000124A038A00044B0A28224386282203863000680C100C090C10008388000069081000CEF +S325000124C04800AAA1900100DC808100DC2C04000A4080009038C0FFFF90C2823838E0004331 +S325000124E0B0E2823C3862823838630006390283689101000838A0000690A1000C4800AA655E +S32500012500806103BC390282389101000838A1024C90A1000C38E0016C90E100104BFFF609D2 +S32500012520806103BC38C2823890C10008390100E09101000C38A0016C90A100104BFFF881E6 +S325000125407C0300004181045C80C100DC38C6000190C100DC808100DC2C04000A4180FF783B +S3250001256080C100DC2C06000A4180002038629D94480013F13860FFFF83E100007FE803A6F9 +S32500012580382103B84E8000208101002C7C0800004182040080A1002C88A500007CA5077423 +S325000125A07C050000418203EC8901010C7D0807747C0800004182001838629DA538E100E016 +S325000125C038E7002C90E100084800139938629DA9888100F490810008888100F59081000C2B +S325000125E0888100F690810010888100F790810014A082823C908100188081002C9081001C2C +S32500012600480013614BFFEA3D386100E0386300104BFFF30590628220A08283A438E4000126 +S32500012620B0E283A4B0828224386100E0386300144BFFF2E59062823838E00045B0E2823C60 +S32500012640806103BC38C2823890C100088121002C9121000C38C2C5C890C100104BFFFA19F5 +S325000126607C030000408000183860FFFF83E100007FE803A6382103B84E8000203882C5C8A9 +S3250001268039440004906100D82C030020418002CC890A00005508402E88CA00017D0833782A +S325000126A05508801E88EA000254E7402E888A00037CE723787D083B782C0806EB4082029C2B +S325000126C088EA000454E7402E88AA00057CE72B7854E7801E88CA000654C6402E890A000744 +S325000126E07CC643787CED337888AA000854A5402E890A00097CA5437854A5801E888A000AF6 +S325000127005484402E88CA000B7C8433787CAC2378890A000C5508402E88CA000D7D083378A8 +S325000127205508801E88EA000E54E7402E888A000F7CE723787D083B78910100C8918100CCDF +S325000127407CC8621491A100D07CC66A1490C100C488AA001454A5402E890A00157CA54378B0 +S3250001276054A5801E888A00165484402E88CA00177C8433787CA5237838629DD090A100B491 +S325000127803FE01FFF63FFFFFF7FE8283991010008480011D14BFFE8AD38629DDF80C100D003 +S325000127A090C10008480011BD808100B43FE01FFF63FFFFFF7FE42039908100BC38E2C5C821 +S325000127C039A70024808100D83944FFE0816100D0916100D47C0A000040820050806103BC09 +S325000127E0388282389081000838E2C5C890E1000C39000200910100104BFFFA59816100D4F1 +S325000128007C6A1B787C030000408000183860FFFF83E100007FE803A6382103B84E800020D5 +S3250001282038C2C5C839A60004914100D87C0B5000418100087D6A5B78806100BC91A100B89B +S3250001284091A10008914100DC9141000C4800A715818100CC814100DC80A100BC7D05521476 +S32500012860910100BC80A100B87DA5521491A100B880A100D47D6A285080A100D87D4A28502C +S32500012880914100D8916100D47C0B00004181FF487C0C000040820088806103BC38C282380B +S325000128A090C10008390000039101000C38A29DE690A10010900100144BFFF47138629DE9CC +S325000128C080E100C890E1000880A100C490A1000C4800109138629DF1810100B4910100084C +S325000128E0480010814BFFE75D4800137D4BFFD8B580C100B43FE01FFF63FFFFFF7FE630395B +S325000129007CC803A64E8000217C03037883E100007FE803A6382103B84E80002038629DE24B +S32500012920918100084800103D81A100B8814100D8816100CC916100D4900100CC80E100BC7F +S3250001294038E70FFF3FE0FFFF63FFF0007FE7383990E100BC4BFFFE80806103BC38C28238B4 +S3250001296090C100089001000C39029DBF9101001038A0000190A100144BFFF3B13860FFFF7F +S3250001298083E100007FE803A6382103B84E80002038C100E038C6006C90C1002C4BFFFC0CA8 +S325000129A03861024C3863001C390100E03908001C9101000838A0000690A1000C4800AB0D46 +S325000129C0814100287C030000418200084BFFFB7C88E100E12C0700014082FB7088C100E225 +S325000129E02C0600064082FB647C0A00004182FB747D435378388100E03884002C908100089A +S32500012A004800AA617C0300004182FB584BFFFB3C38610030914100084800A9E13861003008 +S32500012A203880003A908100084800A2E17C0300004182004038E100309061002C7C0338001A +S32500012A404182FA1488A3FFFF7CA507742C05005C408200084BFFFA0038C1003090C100289C +S32500012A6038C3000190C1002C980300004BFFF9E8390100309101002C4BFFF9DC3821FFF081 +S32500012A807C691B7880A28014814500047D254B783929FFFF7C050000408100187C0703781A +S32500012AA07C0750404080FFE838E700014BFFFFF4382100104E8000203821FFF08102801442 +S32500012AC0810800047D0341D638A003E87D482BD741810008394000017C0903787C095040E8 +S32500012AE040800010392900017C0950404180FFF8382100104E8000207FE802A697E1FFF002 +S32500012B00806280284BFFD6F580A2801480E5000038E7000190E500004BFFECA18102823053 +S32500012B207C0800004182000C7D0803A64E80002183E100007FE803A6382100104E80002053 +S32500012B407FE802A697E1FFB88142801480CA000838E003E87CC63BD690CA00044BFFD67D36 +S32500012B60906100443860000A4BFFFF154BFFD66D808100447CE4185090E100447C07000047 +S32500012B80408000084BFFFFD83861002881028014810800049101000848009D69386100203F +S32500012BA0810280148108000C5504103A7D0822145508083C38A003E87D082BD69101000880 +S32500012BC048009D253861003039010008392100288089000080A900049088000090A80004CD +S32500012BE038A1001038C10020810600008126000491050000912500044800A0DD38610028C4 +S32500012C00810100445508103A9101000848009CD93861003838C10008390100308128000004 +S32500012C208088000491260000908600043881001038A1002880C500008105000490C40000C3 +S32500012C40910400044800935939010004392100388089000080A900049088000090A8000446 +S32500012C6048009DD581428014906A0004810A00047C0800004082000C38800001908A000486 +S32500012C8080AA000C38C000047CA533D638E000327CA53BD63865FFFF906280284BFFD55DA4 +S32500012CA083E100007FE803A6382100484E8000207FE802A697E1FFE89061001C7C0903788F +S32500012CC080A282347C09280040800060912100145523103A38C226107C6332148063000088 +S32500012CE08101001C910100084800A779812100147C030000408200245523103A38822690E0 +S32500012D007C6322148063000083E100007FE803A6382100184E8000203929000180A28234A6 +S32500012D207C0928004180FFA87C03037883E100007FE803A6382100184E8000207FE802A69B +S32500012D4097E1FF28816100E03CE0002090E100A87C0300004182021080E280A080E7000079 +S32500012D6090E1000838E100B490E1000C48002AA9814100A87C030000418100183860FFFF15 +S32500012D8083E100007FE803A6382100D84E800020980A0000386100B49141000838A003FFF6 +S32500012DA090A1000C48001FA57C6A1B787C030000418100183860FFFF83E100007FE803A6E7 +S32500012DC0382100D84E80002080A100A87CA51A1498050000806100A838630400810100A8C6 +S32500012DE09101000838CA000190C1000C4800A175808100A8396404007D6A5B787D6C5B78B4 +S32500012E00888A00007C8407747C04000041820028890A00007D0807742C08000D4082011804 +S32500012E20394A0001888A00007C8407747C0400004082FFE0980B00007D83637838E10020A2 +S32500012E4090E10008388000209081000C38C2886B90C1001048005EF1906100AC7C0A03787A +S32500012E60808100AC7C0A200040800044914100B05543103A38A100207C632A148063000097 +S32500012E8038E0003D90E1000848009E8181828234814100B07C03000040820028394A0001DE +S32500012EA0808100AC7C0A20004180FFC47C03037883E100007FE803A6382100D84E800020A7 +S32500012EC039630001980300005547103A390100207CE7421480E700007CE758502C07001DF8 +S32500012EE0418000185546103A38A100207CC62A1480C600009806001B5587103A38A226105F +S32500012F007CE72A145546103A38A100207CC62A1480C6000090C700005588103A38C2269037 +S32500012F207D08321491680000388C0001908282344BFFFF6C888A00007C8407742C040009BE +S32500012F404082000C38E0002098EA00007D685B78396B0001892A00007D29077499280000F0 +S32500012F604BFFFEC07C0B00004182005C7D635B7890010008388003FF9081000C4800A5BDCF +S32500012F807C030000408200183860FFFF83E100007FE803A6382100D84E8000203862885036 +S32500012FA0480009C1806100A880E100E090E100084800A449806100A84800A4117C6A1B7881 +S32500012FC04BFFFE144BFFD5C190610018806100A880C1001890C100084800A421806100A8D4 +S32500012FE04800A3E97C6A1B784BFFFDEC7FE802A697E1FFD89061002C8121003088A90000CC +S325000130007CA507742C050020408200183929000188A900007CA507742C0500204182FFF0AF +S325000130207C0A03789141001C2C0A0006408000C0888900007C8407747C04000040820018F8 +S325000130403860FFFF83E100007FE803A6382100284E8000203889000188A900007CA5077461 +S3250001306098A10024890400007D0807747C080000408200183860FFFF83E100007FE803A6F7 +S32500013080382100284E8000203904000191010020888400007C840774988100259801002646 +S325000130A03861002490010008388000109081000C48009EB58141001C812100208101002CE5 +S325000130C07D08521498680000890900007D0807742C08003A4082000839290001394A00014D +S325000130E09141001C2C0A00064180FF487C03037883E100007FE803A6382100284E800020BA +S325000131007FE802A697E1FFB87C691B783861002C3902886D910100089121000C81010050D3 +S3250001312091010010480007F97C09037880C282347C093000408000489121001C5523103A59 +S3250001314038E226107C633A14806300003881002C9081000838C0001C90C1000C4800A1F5BB +S325000131608121001C7C030000418200283929000180C282347C0930004180FFC07C03037896 +S3250001318083E100007FE803A6382100484E80002081010054900800345525103A388226904F +S325000131A07CA5221480A5000090A1002880E1002888E700007CE707747C07000041820040D7 +S325000131C080C1002888C600007CC607742C0600204182035080E1002888E700007CE7077436 +S325000131E02C0700094182033C80C1002888C600007CC607747C060000408200183860000121 +S3250001320083E100007FE803A6382100484E80002080610028388288729081000838C00005D1 +S3250001322090C1000C4800A12D814100547C030000408200D48101002839080005910100283F +S325000132407D49537838CA001B7C0930404080002C80A1002888A500007CA507747C05000045 +S325000132604182001880C1002888C600007CC607742C0600204082005C9809000080810028BE +S32500013280888400007C8407747C0400004182FF2081010028890800007D0807742C080020AF +S325000132A0408200084BFFFF0880810028888400007C8407742C040009408200084BFFFEF001 +S325000132C080A1002838A5000190A100284BFFFFB080E1002888E700007CE707742C0700095C +S325000132E04182FF9880A10028388500019081002888A500007CA5077498A9000039290001C0 +S325000133004BFFFF448061002838E2887890E10008388000059081000C4800A0397C03000003 +S3250001332040820028806100283863000539010028910100089001000C48009C2D80A10054D4 +S325000133409065001C4BFFFF388061002838A2887E90A1000838E0000490E1000C48009FF53D +S325000133607C03000040820028806100283863000438C1002890C100089001000C48009BE952 +S3250001338081010054906800204BFFFEF480610028390288839101000838A0000490A1000CFA +S325000133A048009FB17C03000040820028806100283863000438810028908100089001000CC6 +S325000133C048009BA580C10054906600244BFFFEB08061002838C2888890C10008390000050D +S325000133E09101000C48009F6D7C03000040820028806100283863000538E1002890E1000808 +S325000134009001000C48009B6180810054906400284BFFFE6C806100283882888E90810008AD +S3250001342038C0000390C1000C48009F29812100547C0300004082003C3869002C80A1002894 +S3250001344038A5000390A100084BFFFBA52C03FFFF4082FE2C806100543863002C90010008B4 +S32500013460388000069081000C480098C54BFFFE1080C900342C0600084080FE0480A9003497 +S3250001348054A520367CA54A143945003881010028890800007D0807747C0800004182001807 +S325000134A080E1002888E700007CE707742C07002040820018980A000080C9003438C60001E4 +S325000134C090C900344BFFFDB881010028890800007D0807742C080009408200084BFFFFD8F6 +S325000134E07D445378394A000180A10028390500019101002888A500007CA5077498A400006E +S325000135007CE9505081090034550820367CE8385038E7FFC82C07000F4180FF744BFFFF9805 +S325000135208101002839080001910100284BFFFC947FE802A697E1FFF09061001480C1001830 +S3250001354090C100084BFFDA118061001480A1001890A100084800729183E100007FE803A6B0 +S32500013560382100104E8000207FE802A697E1FFD0386295484BFFF73D7C691B787C090000A5 +S32500013580418200247D234B789121002C38A2955B90A1000848009C7D8121002C7C0300004B +S325000135A04182009C3C80FFC260841054908282F4900100247C090000418200187D234B78E0 +S325000135C0900100089001000C4800999D90610024900100283862955F4BFFF6D981210028F1 +S325000135E07C03000041820014900100089001000C480099757C691B787C090000408200081B +S32500013600392025808061002491210008388281909081000C38C281D890C100103D00FFC24C +S325000136206108374C910100144BFFD86183E100007FE803A6382100304E8000203CE0FFC2A6 +S3250001364060E7363090E282F44BFFFF687FE802A697E1FFF09061001480C1001870C8007F92 +S32500013660910100182C08001040820010386295644800037981010018806100149101000803 +S3250001368048006A4D83E100007FE803A6382100104E8000207FE802A697E1FFE090610024DE +S325000136A09001001880C2801480C6000090C100148101002C7C0800004182001C80A2801412 +S325000136C080A5000080C100147CA62850280500FA4181010480628190480069517C691B7874 +S325000136E02C03FFFF408200084BFFFFC82C03000D408200083920000A2C09007F40820008D4 +S32500013700392000089121001C2C090015408200C03900000A99010013386100133880000152 +S325000137209081000880C282F47CC803A64E80002181810024816100288141001C812100180D +S325000137402C0A0008408200187C0900004081FF5838E9FFFF90E100184BFFFF4C2C0A000A30 +S32500013760408200207CEC4A14980700007D234B7883E100007FE803A6382100204E800020BD +S325000137802C0A0015408200183860FFFF83E100007FE803A6382100204E8000207C095800AF +S325000137A0408200187D635B7883E100007FE803A6382100204E8000203909000191010018AD +S325000137C07C8C4A14994400004BFFFEDC992100134BFFFF483860FFFE83E100007FE803A614 +S325000137E0382100204E8000207FE802A697E1FFE090610024808100289804000080E100308A +S325000138007C0700004182001880810030888400007C8407747C040000408200FC7C06037850 +S3250001382090C10018808100187C040000418200683862956780C1002490C1000880810030CF +S325000138409081000C4800011D8061002880E1002C90E1000880C1001890C1000C4BFFFE3998 +S325000138607C691B782C03FFFE4182008C2C03FFFF4182FFB48101002C7C0940004180002C4B +S3250001388038629580480000DD808100187C0400004082FFA03862957980E1002490E10008AD +S325000138A0480000C14BFFFFA47C0900004082001080E100187C070000408200187C030378E4 +S325000138C083E100007FE803A6382100204E8000208061002880A1003090A1000848009B1D73 +S325000138E07C03037883E100007FE803A6382100204E8000203862957E38800001908100086D +S3250001390080C282F47CC803A64E8000217C0903784BFFFF6438C000014BFFFF087FE802A606 +S3250001392097E1FFE89061001C38C3010090C10008808100209081000C38E1002038E7000425 +S3250001394090E10010480007F18081001C7C64185083E100007FE803A6382100184E80002067 +S325000139607FE802A697E1FEE09061012480E282F47C070000408200187C03037883E1000032 +S325000139807FE803A6382101204E8000203861002038C1002038C6010090C1000881010124D7 +S325000139A09101000C38C1012438C6000490C1001048000785390100207C881850386100208E +S325000139C09081001C90810008810282F47D0803A64E8000218061001C83E100007FE803A613 +S325000139E0382101204E8000207FE802A697E1FEE0812282F4906101247C0900004182007408 +S32500013A003862958F38800007908100087D2803A64E8000213861002038A1002038A501003C +S32500013A2090A1000880E1012490E1000C38A1012438A5000490A10010480006FD38E100209F +S32500013A407D071850386100209101000880E282F47CE803A64E8000213862959738800001CD +S32500013A609081000880C282F47CC803A64E8000214BFFC7154BFFC70D4BFFFFFC7FE802A6FA +S32500013A8097E1FFE0808280148124002038C0000190C90030808908403FE0FFFF63FFFFFE1E +S32500013AA07FE4203990890840B0090968B0090964B0090960B0090962B0090966B009095210 +S32500013AC0B0090950B0090954B009095690090ABC90090AB8B0090AC29121001C90090AC42B +S32500013AE04BFFC6998101001C3CA0000060A58001B0A809C080C1001CA0C609C070C6000132 +S32500013B00418200184BFFC67580C1001CA0C609C070C600014082FFF0386281E038E2B3C83A +S32500013B2090E10008388004009081000C480065E9386281E03CC0FA2060C6240090C10008E2 +S32500013B40390004009101000C480065F183E100007FE803A6382100204E8000207FE802A6FB +S32500013B6097E1FFE89061001C4BFFC639906100108102801481080020910100144BFFC5FD16 +S32500013B8081010014A10809C071080001418200184BFFC5E981010014A10809C07108000147 +S32500013BA04082FFF08081001C5484402E80A1002054A520367C842B7880C1002454C6083CF4 +S32500013BC07C8433786084000180A10014B08509C04BFFC5A980E10014A0E709C070E7000146 +S32500013BE0418200184BFFC59580E10014A0E709C070E700014082FFF0806100104BFFC5C1B0 +S32500013C0083E100007FE803A6382100184E8000203821FFE85465183838A5FFF8810100200B +S32500013C20710800075508183880E1002470E700077D083B787D0B283080E280148127002097 +S32500013C4080E90AEC390000FF7D0828307D0840F87CE740387CE75B7890E90AEC382100183B +S32500013C604E8000207FE802A697E1FFE080E2801480E7002039270A209121001C80E90000AB +S32500013C8070E70030418200543860000538C0000490C100089001000C4BFFFEC53860000744 +S32500013CA039000004910100089001000C4BFFFEB1386000014BFFEDC980A1001C80E5000055 +S32500013CC03FE0FFFF63FFFFCF7FE7383990E50000386000044BFFCA9983E100007FE803A687 +S32500013CE0382100204E8000207FE802A697E1FFE07C681B78386281E0900100085507183839 +S32500013D0090E1000C90010010480065997C681B789061001C7C030000408200103862833B0B +S32500013D204BFFFCC98101001C7D03437883E100007FE803A6382100204E8000207FE802A6AA +S32500013D4097E1FFE89061001C7C030000418200384BFFC4298121001C386281E07528E00009 +S32500013D603CA020007C0828004182002C7D274B7890E1000880810020548418389081000C5F +S32500013D80480063B983E100007FE803A6382100184E8000203FE0FFFF63FFFFFF7FE7483981 +S32500013DA04BFFFFD07FE802A697E1FFE83E0000006210900081E1002481C100207C6A1B78D4 +S32500013DC091C3000C9061001C80E300007C070000408200247DC373784BFFFF113E000000E0 +S32500013DE06210900081E1002481C100208141001C906A000080C1002838C6000F3FE0FFFF67 +S32500013E0063FFFFF07FED3039808A00047C0400004082002C91A100287C6E69D64800518558 +S32500013E203E0000006210900081E1002481C1002081A100288141001C906A000480CA0000E3 +S32500013E407C060000418201A880AA00047C0500004182019C80AA000474A5E0003CC020001B +S32500013E607C05300041820174808A00047C8C23787C0B03787C0B700040800044556418389B +S32500013E8080EA00007C843A14B004000255661838808A00007CC622149186000455651838FB +S32500013EA0810A00007CA54214B20500007D8C6A14396B00017C0B70004180FFC4556818388E +S32500013EC080CA00007D083214A0A8FFF860A52000B0A8FFF8900A000891EA0020808A0010BC +S32500013EE07C040000408200187DE37B784BFFFDFD81E100248141001C906A0010810A0014BD +S32500013F007C0800004082001855E3103A4800509581E100248141001C906A001480EA0010A1 +S32500013F207C070000418200A080CA00147C060000418200947C0B03787C0B7800408000504C +S32500013F405567103A80AA00147CE72A14900700005564183880EA00107C843A149004000475 +S32500013F6055661838808A00107CC62214B00600025568183880CA00107D083214B0080000FB +S32500013F80396B00017C0B78004180FFB855651838810A00107CA54214A0E5FFF860E72000FF +S32500013FA0B0E5FFF8900A0018900A001C900A00247C03037883E100007FE803A63821001869 +S32500013FC04E8000203860FFFF83E100007FE803A6382100184E800020808A00043FE0FFFF58 +S32500013FE063FFFFFF7FE420394BFFFE843860FFFF83E100007FE803A6382100184E80002069 +S325000140003821FFF0818282D0816100187C6A1B782C0B00094082005C7D8B6378388C00087C +S325000140203FE0FFFF63FFFFF87FEC20397D675B78396B0001918282D07C07600040800014C7 +S32500014040808A0000810A00047C0440404180000C382100104E80002080EA000039270001D1 +S32500014060912A000038800020988700004BFFFFC080A30000808300047C0520404080001C97 +S325000140808103000039280001912300009968000038AC000190A282D02C0B000A408200080A +S325000140A0900282D0382100104E800020814283E07C6907747D26077470C6007F7CC90774A5 +S325000140C07D24077438C285A87C843214888400007C8407747C0400004082002C2C0A001E07 +S325000140E04180000C386000014E8000207D26077438E285A87CC63A14390A0001910283E036 +S32500014100994600007D250774390285A87CA5421488A500007CA5077454A5103A38C284D063 +S325000141207CA5321480E1000890E500007C0303784E8000207FE802A697E1FFC890610018F4 +S3250001414080E1004090E1001C80810048908100208141004438EA000190E10044894A0000FF +S325000141607D4A07742C0A0025418200487C0A00004082003080A1001880E1001C7C05384069 +S325000141804080000C80810018980400008061001883E100007FE803A6382100384E800020AB +S325000141A038610018914100084BFFFE594BFFFFA49001002438A0FFFF90A100289001002C3E +S325000141C03967000191610044894700007D4A07747C0C03782C0A002D4082001C39800001F1 +S325000141E07D6A5B78396B000191610044894A00007D4A07742C0A00304180000C2C0A00396C +S325000142004081010C7C0C00004182001080A100247D050050910100242C0A002E41820084F6 +S325000142207C0A00004082000C38CBFFFF90C100443861001838A285A87146007F7CA5321438 +S3250001424088A500007CA5077454A5103A38C284D07CA5321480A500007CA803A64E800021B5 +S325000142607C0300004080002C7CA300508081002C7C852B7890A1002C81410044396A000185 +S3250001428091610044894A00007D4A07744BFFFF9480E100207CE71A1490E100204BFFFEB450 +S325000142A07D6A5B78396B000191610044894A00007D4A07742C0A00304180FF682C0A003950 +S325000142C0408100084BFFFF5C808100287C040000408000089001002880C1002854C5103A73 +S325000142E07CC62A1454C6083C7CC6521438C6FFD090C100287D6A5B78396B00019161004456 +S32500014300894A00007D4A07744BFFFFAC810100245507103A7D083A145508083C7D085214E1 +S325000143203908FFD0910100247D6A5B78396B000191610044894A00007D4A07744BFFFEB806 +S325000143407FE802A697E1FFE0906100244800907D7C6A1B789061001C80E1002C7C070000F0 +S325000143604180003C9141001C80C1002C7C0A30004080002C80610028388000209081000842 +S325000143804BFFFC8180C1001C394600019141001C80C1002C7C0A30004180FFDC81610024BF +S325000143A07D665B78396B00019161001488C600007CC607747C0600004182003480E1003080 +S325000143C07C0700004182FFDC8061002890C100084BFFFC31816100148141001C8101003056 +S325000143E03908FFFF910100304BFFFFB880C1002C7C0600004080004880A1002C7D0500509E +S325000144009101002C9141001C80A1002C7C0A28004080002C80610028390000209101000806 +S325000144204BFFFBE180A1001C394500019141001C80A1002C7C0A28004180FFDC83E10000AA +S325000144407FE803A6382100204E8000207FE802A697E1FFA881C282E881A100607C6C1B7806 +S325000144607C0F037880C3001470C600072C0600044181015C418201442C060001418201281F +S325000144802C0600024182010080AC00088145000038E0000490E1002880CC001470C60004D4 +S325000144A04082000C7C0A0000418000D0980100573960001C7FEA6B967FFF69D67CFF505029 +S325000144C0392700302C09003940810014392900277C0E0000418200083929FFE038C1003AB0 +S325000144E07CC65A14992600002C0B0002408000547C0F0000418200183881003A396BFFFFFE +S325000145007C845A1438A0002D98A400003861003A7C635A149181000880EC000C90E1000CB6 +S3250001452038E0FFFF90E100104BFFFE198061002883E100007FE803A6382100584E80002060 +S325000145407D4A6B96810C00107C0800004180001880EC00103900001E7CE740507C0B38000D +S32500014560408000107C0A0000418100084BFFFF84396BFFFF4BFFFF407D4A005039E00001EB +S325000145804BFFFF2C80AC000880A500007CA907347D2407347C8A2378388000049081002874 +S325000145A04BFFFEF8808C00088144000038C0000490C100284BFFFEE4810C000881480000DC +S325000145C038A0000490A100284BFFFED02C060005418200302C060006418200084BFFFEAC66 +S325000145E080AC000880A500007CA907345524043E7C8A237838800004908100284BFFFE9CC6 +S3250001460080E300088147000038800004908100284BFFFE887FE802A697E1FFE87C671B78B7 +S32500014620386280B890E100089001000C3880FFFF908100104BFFFD0D7C03037883E1000002 +S325000146407FE803A6382100184E8000207FE802A697E1FFE07C681B7880E3000880E7000035 +S3250001466098E1001E9801001F3861001E910100088088000C9081000C3880FFFF908100108B +S325000146804BFFFCC13860000483E100007FE803A6382100204E8000207FE802A697E1FFF01F +S325000146A03900000A910100084BFFFDA583E100007FE803A6382100104E8000203860FFFECA +S325000146C04E8000203860FFFF4E8000207FE802A697E1FFF038E0000890E100084BFFFD719A +S325000146E083E100007FE803A6382100104E8000207FE802A697E1FFE87C671B788063000819 +S325000147008063000090E100088107000C9101000C81070010910100104BFFFC2938600004BF +S3250001472083E100007FE803A6382100184E8000203860FFFC4E8000207FE802A697E1FFF0A8 +S3250001474038A0001090A100084BFFFD0583E100007FE803A6382100104E8000207FE802A60B +S3250001476097E1FFE839000001910282E838C0001090C100084BFFFCD9900282E883E10000BC +S325000147807FE803A6382100184E8000207FE802A697E1FFF038E0002590E100084BFFF865D0 +S325000147A07C03037883E100007FE803A6382100104E8000207FE802A697E1FFD89061002CB2 +S325000147C03862889880A1003090A100084BFFF19581A100308181002C3942A1F83902A1F856 +S325000147E0390801407C0A40404080003080CA00047C0D30004082001080EA000C7C0C38002B +S32500014800418201B4394A00143902A1F8390801407C0A40404180FFD83962A1F838C2A1F8C7 +S325000148203946001438C2A1F838C601407C0A30404080002C808A0000810B00007C044000D4 +S32500014840418100087D4B5378394A001438C2A1F838C601407C0A30404180FFDC7D6A5B783F +S3250001486080CC001480EC00107D6639D69141002480CA00087C0600004182011480AA001087 +S325000148807C055800418001089161001C916A0010386288BD80AC000C7CAD2A14810C00103A +S325000148A07CA541D690A100084BFFF0B98141002C806A000080EA000C812100307CE93A14BA +S325000148C080AA00107CE729D690E1000880AA00087CA803A64E8000218141002C7C03000061 +S325000148E040800020386288CF4BFFF0797C03037883E100007FE803A6382100284E80002050 +S32500014900806A00008101002481080008910100088101001C9101000C80CA00047CC803A65E +S325000149204E800021816100308141002480A1001C7C03280041820020386288E14BFFF02560 +S325000149407C03037883E100007FE803A6382100284E8000208082801480840000908A0000BF +S3250001496080C1002C90CA000C916A0004386288F3916100084BFFEFED8061002483E10000C0 +S325000149807FE803A6382100284E8000207D635B789161001C90010008480045818161001C2B +S325000149A08141002481A100308181002C906A00084BFFFED89141002480A2801480A5000097 +S325000149C090AA0000386288A791A100084BFFEF958061002483E100007FE803A638210028CB +S325000149E04E8000207FE802A697E1FFD89061002C3862890580E1003090E100084BFFEF6577 +S32500014A00816100308141002C2C0B0002418001AC80EA00347C0B3800408001A0810A003867 +S32500014A202C08000C418201802C080010418200183860FFFF83E100007FE803A63821002841 +S32500014A404E800020556B083C810A0030812A00107D0849D6916100247C0B40404180001451 +S32500014A60386289114BFFEF85816100248141002C808A001080EA00147C8439D67C8B2396E2 +S32500014A80810A00147C8441D680EA003C7C843A1480EA0010810A00147CE741D67FEB3B9697 +S32500014AA07FFF39D67CFF585090E100187D43537890810020908100084BFFFCFD8181002C70 +S32500014AC07C6A1B7880C3000881010018396800017CC6421488C6000090C1002480CC001018 +S32500014AE080EC00147CC639D67C0B3000418000287D836378808C001480A100207C852214CB +S32500014B00908100084BFFFCB18181002C7C6A1B787C0B0378810A00087D085A1489080000BE +S32500014B205508402E808100247C8A437880EC00382C07000C4082002080C1003070C6000150 +S32500014B404182005C554AE13E280A0FF841800008614AF0003CE0000060E7FFF87C0A38407C +S32500014B60408000347D4453783862891880A1003090A10008908100249081000C4BFFEDE57B +S32500014B808061002483E100007FE803A6382100284E8000203880FFFF4BFFFFD0714A0FFF8E +S32500014BA04BFFFFA85567083C7D0B3A14392000027D684BD64BFFFE943860FFFF83E10000F0 +S32500014BC07FE803A6382100284E8000207FE802A697E1FFD87C691B7881030000910100243F +S32500014BE03862892A9121002C390900049101000880C1003090C1000C4BFFED6981A1002CE7 +S32500014C008181003081610024808D00147C04000040820070810B00107D0C41D680CB0014E7 +S32500014C207D0831D680AB002454A528347C082800418000183860FFFF83E100007FE803A6AE +S32500014C40382100284E800020808B004080AB00147CAC29D67C842A143862893D9181000875 +S32500014C60908100209081000C4BFFECF98061002083E100007FE803A6382100284E800020CC +S32500014C80808D001C7C0C20004180001080AD00187C050000408200A87C0A0378812D001478 +S32500014CA0914100207C0A6000418200507D635B78912100084BFFFD3181A1002C818100309D +S32500014CC0816100247C691B787C030000408000183860FFFF83E100007FE803A6382100286D +S32500014CE04E80002080C1002039460001914100207C0A60004082FFB8914D001C912D0018BD +S32500014D0038E9FFFE80CB00147CE731D680AB00447CE53A14386289509181000890E1002069 +S32500014D2090E1000C4BFFEC3D8061002083E100007FE803A6382100284E800020814D001CAE +S32500014D40812D00184BFFFF5C7FE802A697E1FFC87C6A1B788903000F7108001040820050E4 +S32500014D60808A0020810A00107C044000418000187C03037883E100007FE803A638210038CF +S32500014D804E80002080EA0020810100447CE74214808A00107C07200040810014810A0010E8 +S32500014DA0812A00207D09405091010044810100409101001C7C0B03789161003080E10044FC +S32500014DC07C0B38004080010C7D43537880CA00209141003C80EA000080E700187CC63BD601 +S32500014DE090C100084BFFFDE97C6A1B787C030000408000183860FFFF83E100007FE803A649 +S32500014E00382100384E8000208061003C80630000914100084BFFF9A18181003C7C03000091 +S32500014E20408200183860FFFF83E100007FE803A6382100384E80002080CC002080EC000030 +S32500014E4080E700187FE63BD67FFF39D67D5F3050810300087DA8521480C1004480810030A0 +S32500014E607D64305080EC000080E700187CEA38507C0B380040810010810C00008108001833 +S32500014E807D6A40508061001C91A100089161002C9161000C480080CD8161002C8141003CA0 +S32500014EA080E1001C7CA75A1490A1001C808A00207CE45A1490EA002080E100307D675A141B +S32500014EC09161003080E100447C0B38004180FEFC7D635B7883E100007FE803A638210038D2 +S32500014EE04E8000207FE802A697E1FFC08883000F7084001040820020386289634BFFEA6558 +S32500014F003860FFFF83E100007FE803A6382100404E8000209061004480C1004890C10008E2 +S32500014F2048000EA981210044900900207D234B78388100209081000838E0002090E1000CC2 +S32500014F404BFFFE092C030020408201103862897B388100209081000838C1002038C6000828 +S32500014F6090C1000C4BFFE9FD806100443863000438A1002090A1000838E0000890E1000C0A +S32500014F8048008549812100447C030000418200084BFFFF9C3869000C38C1002038C6000813 +S32500014FA090C10008390000039101000C4800851D812100447C030000418200084BFFFF70E4 +S32500014FC088A1002B70A500084182002838628995388100209081000838C1002038C60008A5 +S32500014FE090C1000C4BFFE97D812100444BFFFF4088A1002B98A9000F88E1003B54E7402E3D +S325000150008901003A7CE7437890E900148881003F5484402E88A1003E7C842B785484801E0C +S3250001502088A1003D54A5402E88C1003C7CA533787C842B7890890010900900189009001C19 +S32500015040900900203860000183E100007FE803A6382100404E8000207C03000041800018A4 +S325000150607C03037883E100007FE803A6382100404E8000203860FFFF83E100007FE803A62A +S32500015080382100404E8000207FE802A697E1FFD07C6D1B7880E1003890E3000C38C002009E +S325000150A090C3001038800001908300147C0903787DA36B7891A100349121001C91210008B5 +S325000150C04BFFF6F581A100347C6A1B787C03000040820020386289AD4BFFE8893860FFFF43 +S325000150E083E100007FE803A6382100304E80002081030008890801FE2C08005540820380D4 +S3250001510080C3000888C601FF2C0600AA408203709003000C8123000880C1003C7C06000094 +S3250001512041820010890900152C0800F8408201E8812A000888A900002C0500E9418200381E +S3250001514088C900002C0600EB4082001088E900022C07009041820020386289CD4BFFE805C8 +S325000151603860FFFF83E100007FE803A6382100304E8000207D234B789121002C4800031DFE +S325000151808141002C81210034888A000C5484402E88CA000B7C8433789089001088EA000D30 +S325000151A090E900148089001080A900147C8429D69089001888CA000F54C6402E890A000E4B +S325000151C07CC6437890C9001C888A00109089002088CA001254C6402E890A00117CC643786E +S325000151E090C9002488EA001454E7402E888A00137CE7237890E90028810900287C08000002 +S325000152004082003088EA002354E7402E88AA00227CE72B7854E7801E88CA002154C6402E29 +S32500015220890A00207CC643787CE7337890E90028888A00159089002C88CA001754C6402EAB +S32500015240890A00167CC6437890C900308089001C9089003C8089002080A900307C8429D61D +S3250001526080A9003C7C8522149089004080C9002454C6283480E900107CC63A143946FFFFC9 +S3250001528080C900107D4A33D680C900407CC6521490C900448089002880A900447C85205001 +S325000152A080A900147C842BD6388400029089003480C900342C060FF74080005038E0000CB5 +S325000152C090E9003839000002910900489129004C9009006090090068900900649009006CF7 +S325000152E038A0001098A9005B81090024550828349109005C7C03037883E100007FE803A658 +S32500015300382100304E80002038A0001090A900384BFFFFB4808A0008392401BE3980FFFFD4 +S325000153207C0B03782C0B000440800064890900042C0800544082000C3920003F4BFFFD74C6 +S3250001534088A900042C0500014182001088C900042C0600044082011889090000710800801B +S32500015360418200A88889000B5484402E88E9000A7C843B785484801E890900095508402E4F +S3250001538088A900087D082B787C8C43782C0B0004408200183900FFFF7C0C40004082000C00 +S325000153A0900A000C4BFFFD8C80C1001C7CC6621490CD000C7DA36B78900100084BFFF3F91D +S325000153C07C6A1B787C0300004182001480E3000888E701FE2C070055418200183860FFFF25 +S325000153E083E100007FE803A6382100304E80002080A3000888A501FF2C0500AA4082FFE0E7 +S32500015400900A000C4BFFFD2C88E9000B54E7402E88A9000A7CE72B7854E7801E88C90009D3 +S3250001542054C6402E890900087CC643787CE733787C0760404080002C88C9000B54C6402E45 +S325000154408889000A7CC6237854C6801E88A9000954A5402E88E900087CA53B787CCC2B78BC +S32500015460396B0001392900104BFFFEBC88E900042C0700064082FFEC4BFFFEE0386289C4A0 +S325000154804BFFE4E13860FFFF83E100007FE803A6382100304E8000207FE802A697E1FFE807 +S325000154A07C691B78386289E1888900009081000888C9000190C1000C9121001C890900022E +S325000154C0910100104BFFE49D38628A0180A1001C38A5000390A100084BFFE4898121001C68 +S325000154E038628A138909000C5508402E88A9000B7D082B78910100084BFFE46938628A212B +S3250001550080E1001C88E7000D90E100084BFFE4558121001C38628A308889000F5484402E17 +S3250001552088C9000E7C843378908100084BFFE43538628A3C8101001C8908001091010008A5 +S325000155404BFFE4218121001C38628A4788A9001254A5402E88E900117CA53B7890A1000893 +S325000155604BFFE4018121001C38628A55888900145484402E88C900137C843378908100082B +S325000155804BFFE3E138628A628101001C89080015910100084BFFE3CD8121001C38628A7640 +S325000155A088A9001754A5402E88E900167CA53B7890A100084BFFE3AD8121001C38628A8362 +S325000155C0888900195484402E88C900187C843378908100084BFFE38D8121001C38628A90FB +S325000155E08909001B5508402E88A9001A7D082B78910100084BFFE36D8121001C38628A9C07 +S3250001560088E9001F54E7402E88A9001E7CE72B7854E7801E88C9001D54C6402E8909001C78 +S325000156207CC643787CE7337890E100084BFFE3358121001C38628AA988A9002354A5402E37 +S32500015640890900227CA5437854A5801E888900215484402E88C900207C8433787CA52378CC +S3250001566090A100084BFFE2FD38628AB98101001C89080024910100084BFFE2E938628AC6F8 +S3250001568080A1001C88A5002590A100084BFFE2D538628ADA80E1001C88E7002690E10008B1 +S325000156A04BFFE2C18121001C38628AEC8889002A5484402E88E900297C843B785484801EE4 +S325000156C0890900285508402E88A900277D082B787C844378908100084BFFE28938628AFC15 +S325000156E080E1001C38E7002B90E100084BFFE27583E100007FE803A6382100184E800020EF +S325000157007FE802A697E1FFE8816100207C691B7888C900007CC607742C06002F4082001851 +S325000157203929000188C900007CC607742C06002F4182FFF088A900007CA507747C05000090 +S32500015740418200C088C900007CC607742C060020418200B07C0A037888A900007CA507741E +S325000157607C0500004182001488C900007CC607742C06002F4082001C980B00007D234B7877 +S3250001578083E100007FE803A6382100184E80002088E900007CE707742C0700204082001CAF +S325000157A0980B00007D234B7883E100007FE803A6382100184E8000202C0A001C40820020D5 +S325000157C038628B0E4BFFE19D7C03037883E100007FE803A6382100184E8000207D655B7845 +S325000157E0396B00017D264B783929000188C600007CC6077498C50000394A00014BFFFF5CA3 +S325000158007C03037883E100007FE803A6382100184E8000207FE802A697E1FFD080E1003CC1 +S325000158207C641B7838C0000380A4004C8104005090A7000080A400549107000490A7000824 +S3250001584038C6FFFF3884000C38E7000C7C0600004181FFD88061003838A1001490A10008F8 +S325000158604BFFFEA1906100387C030000418200508061003C38A1001490A100084BFFF66991 +S325000158802C03FFFF418200247C030000418200084BFFFFC47C03037883E100007FE803A628 +S325000158A0382100304E8000203860FFFF83E100007FE803A6382100304E8000203860000150 +S325000158C083E100007FE803A6382100304E8000207FE802A697E1FFA880E1006090E100086E +S325000158E038C1003490C1000C4BFFFF2D814100602C03FFFF418204207C030000418203F82E +S325000159002C030001418203B43860002090010008480036097C6B1B7838A0002038610034BF +S3250001592090A1003090A10008916100289161000C4800040581410028810100307C03400002 +S3250001594041820020806282CC4BFFE0193860FFFF83E100007FE803A6382100584E80002041 +S3250001596088CA000054C6402E888A00017CC6237854C6801E88AA000254A5402E88EA00038E +S325000159807CA53B787CC62B782C0606EB4182004C38628B7C890A00005508402E88CA0001C3 +S325000159A07D0833785508801E88EA000254E7402E888A00037CE723787D083B7891010008B3 +S325000159C04BFFDFA13860FFFF83E100007FE803A6382100584E80002088EA001454E7402E1E +S325000159E088AA00157CE72B7854E7801E890A00165508402E892A00177D084B787CE74378D6 +S32500015A0074E7E0003C8020007C0720004182027488CA001454C6402E88EA00157CC63B7822 +S32500015A2054C6801E890A00165508402E88AA00177D082B787CC6437890C1002C890A0004B1 +S32500015A405508402E88CA00057D0833785508801E88EA000654E7402E888A00077CE72378BA +S32500015A607D083B7838628BA791010030910100084BFFDEF13861003480A1003090A100084F +S32500015A808101002C9101000C480002AD81610030814100287C03580041820020806282CCD6 +S32500015AA04BFFDEC13860FFFF83E100007FE803A6382100584E80002080E1002C7C8B3A146B +S32500015AC038840FFF3FE0FFFF63FFF0007FE420399081002C88AA000854A5402E890A000950 +S32500015AE07CA5437854A5801E888A000A5484402E88CA000B7C8433787CA5237838628BAB36 +S32500015B0090A1003090A100084BFFDE593861003480E1003090E1000880A1002C90A1000C02 +S32500015B204800021581410028810100307C03400041820020806282CC4BFFDE293860FFFFAA +S32500015B4083E100007FE803A6382100584E80002038628BAF88CA000C54C6402E888A000D52 +S32500015B607CC6237854C6801E88AA000E54A5402E88EA000F7CA53B787CC62B7890C100084F +S32500015B80888A00145484402E88EA00157C843B785484801E890A00165508402E88AA001725 +S32500015BA07D082B787C8443789081000C4BFFDDB581410028890A00145508402E88CA00153F +S32500015BC07D0833785508801E892A00165529402E888A00177D2923787D084B787508E000CF +S32500015BE03CA020007C0828004182004888EA001454E7402E890A00157CE7437854E7801E1D +S32500015C00888A00165484402E88CA00177C8433787CE723787CE803A64E8000217C03037807 +S32500015C2083E100007FE803A6382100584E80002088EA001454E7402E888A00157CE72378F6 +S32500015C4054E7801E88AA001654A5402E890A00177CA543787CE72B783FE0FFFF63FFFFFFAC +S32500015C607FE738397CE803A64E8000217C03037883E100007FE803A6382100584E8000203D +S32500015C8088CA001454C6402E890A00157CC6437854C6801E888A00165484402E88EA0017BB +S32500015CA07C843B787CC623783FE0FFFF63FFFFFF7FE630394BFFFD8438628B4A38A10034BB +S32500015CC038A5000490A1000838E1003438E7000C90E1000C888100439081001080810048F8 +S32500015CE09081001480E1004490E100184BFFDC754BFFFC1838628B3C914100084BFFDC658B +S32500015D003860FFFF83E100007FE803A6382100584E80002038628B27914100084BFFDC4542 +S32500015D203860FFFF83E100007FE803A6382100584E8000207FE802A697E1FFD88161003043 +S32500015D409061002C80E1003490E100247C0A03787C0A580040800044392020007C8A5850EB +S32500015D607C044800408000087D2A58508061002C808100249141001C7C845214908100089E +S32500015D809121000C4BFFEFC58141001C906100207C030000418100187D43537883E1000009 +S32500015DA07FE803A6382100284E80002038628BC44BFFDBB1816100308081002080C1001C0E +S32500015DC07D4622144BFFFF8C7FE802A697E1FFE0812100287C6B1B783943000488E9000053 +S32500015DE07CE707747C070000418200147CCB505038C6FFFC2C060008418001047CAB5050BD +S32500015E0038A5FFFC2C050008408000247D455378394A000138C0002098C500007CAB505039 +S32500015E2038A5FFFC2C0500084180FFE4394B000C88A900007CA507747C05000041820014F1 +S32500015E407C8B50503884FFF42C0400034180005C7C8B50503884FFF42C0400034080002428 +S32500015E607D445378394A000138A0002098A400007C8B50503884FFF42C0400034180FFE4AA +S32500015E8038628BC638AB000490A10008390B000C9101000C4BFFDACD83E100007FE803A69D +S32500015EA0382100204E800020888900007C8407742C0400614180001488A900007CA50774B5 +S32500015EC02C05007A4081001C888900007C840774988A000039290001394A00014BFFFF5401 +S32500015EE0890900007D0807743908FFE0990A000039290001394A00014BFFFF3888C900008D +S32500015F007CC607742C06002E4082000C392900014BFFFEEC88A900007CA507742C05006199 +S32500015F204180001488C900007CC607742C06007A4081001C88A900007CA5077498AA0000DF +S32500015F4039290001394A00014BFFFE94888900007C8407743884FFE0988A000039290001CB +S32500015F60394A00014BFFFE787FE802A697E1FFC8900100287C0A03782C0A00044080006074 +S32500015F8091410030554818387C8A4214548428347C88205038A2D7D07C642A149061003443 +S32500015FA09001000838E0011890E1000C48006D818061003080C1003490C100084BFFA6CDC1 +S32500015FC0816100347C0300004181002880810030394400012C0A00044180FFA880610028E1 +S32500015FE083E100007FE803A6382100384E8000207C0A03785547183838C282807CE7321415 +S3250001600080E700007C0700004182FFC4914100245543183838E282807C633A1480630000FF +S32500016020916100084800743D81610034814100247C0300004182000C394A00014BFFFFB897 +S3250001604080810030908B00EC7D635B785548183838E282807D083A14810800047D0803A6B7 +S325000160604E8000217C030000418200084BFFFF603860400038A0000190A100089001000CB0 +S325000160809001001048003E5580E10034906700F43860400038C0000190C100089001000C36 +S325000160A09001001048003E3581410034906A00F839000001910A00F03880000180C10030A6 +S325000160C07C843030810100287D0423789081002838629A1180CA00EC90C100089141000CA8 +S325000160E0808A001C90810010808A0020908100144BFFD87181410034808A00247C040000CC +S325000161004182002C38629A31808A00247484E0003D2020007C04480041820098810A0024CF +S32500016120910100084BFFD83D8141003480CA00287C0600004182001438629A3E80AA0028DA +S3250001614090A100084BFFD81D38629A4B4BFFD8157C0A03782C0A00064080003038629A4D5C +S325000161609141002C80C100347CAA321488A5002C90A100084BFFD7ED80A1002C39450001CD +S325000161802C0A00064180FFD838629A554BFFD7D54BFFAEB181410034806A0020810A00D0A1 +S325000161A0910100089141000C48004AC94BFFFE20810A00243FE0FFFF63FFFFFF7FE8403991 +S325000161C04BFFFF607FE802A697E1FFE82C03000440800080546618387CA3321454A528346A +S325000161E07CA6285038C2D7D07CA5321480A500F07C0500004182005C546718387D033A1468 +S32500016200550828347D0740503922D7D07D484A1480AA00F02C0500014082002438C0000259 +S3250001622090CA00F07D43537891410014810A00BC7D0803A64E800021814100147D435378D7 +S3250001624083E100007FE803A6382100184E8000207C03037883E100007FE803A63821001885 +S325000162604E8000207FE802A697E1FFE84BFFFF597C030000408200187C03037883E1000062 +S325000162807FE803A6382100184E8000203863002C83E100007FE803A6382100184E800020EE +S325000162A07FE802A697E1FFD84BFFFF1D906100207C030000408200187C03037883E100004B +S325000162C07FE803A6382100284E80002080828014808400009081001880610020806300F49D +S325000162E048003C357C6A1B787C0300004082005080A2801480A5000080E100187CA72850E5 +S3250001630054A4083C7CA5221454A518385484482C7CA5205038C000327CA5339680C1003434 +S325000163207C0530404180FFB47C03037883E100007FE803A6382100284E800020810300048C +S32500016340812300007D094050806100309141001C808A000090810008910100249101000C06 +S3250001636048006C018061001C48003B118061002483E100007FE803A6382100284E800020E8 +S325000163807FE802A697E1FFE87C691B7880610020806300009121001C3889002C9081000858 +S325000163A038E0000690E1000C48007121812100207C03000041820028806900003902836826 +S325000163C09101000838A0000690A1000C480070FD812100207C030000408200288061001C24 +S325000163E0806300F49121000848003BA93860000183E100007FE803A6382100184E8000206D +S3250001640080E100247C0700004182000C7D234B7848003A697C03037883E100007FE803A6E2 +S32500016420382100184E8000207FE802A697E1FFD89061002C4BFFFD917C030000408200184A +S325000164407C03037883E100007FE803A6382100284E80002090610024806300F848003BC520 +S325000164602C0340004081002838629A5780A1002C90A100084BFFD4ED7C03037883E1000043 +S325000164807FE803A6382100284E800020386005F0480039919061002080630004810100302D +S325000164A09101000880C1003490C1000C48006AB580610020806300043863000680E10024F4 +S325000164C038E7002C90E1000838A0000690A1000C48006A91812100208081003480C900044F +S325000164E07C8622149089000480610024806300F89121000848003A9D4BFF9CA98121002432 +S325000165009061001C7D234B78810900CC7D0803A64E8000218061001C4BFF9CA53860000170 +S3250001652083E100007FE803A6382100284E8000207FE802A697E1FFF880A300EC54A7183899 +S325000165407CA53A1454A5103A3902A3387CA5421480A5000080C5000060C6003090C50000E0 +S325000165604BFF9C1983E100007FE803A6382100084E8000207FE802A697E1FFD89061002CD7 +S325000165808081002C808400EC548518387C842A145484103A38C2A3387D24321481090020E8 +S325000165A0550818389121002080C900187D08321491010018A1080000710880004082001CFF +S325000165C08061002C806300F84800394D7C691B787C0300004082001483E100007FE803A6BD +S325000165E0382100284E80002080A3000480C300007CA6285080610018806300049121001C73 +S32500016600810900009101000890A1002490A1000C4800695180C1001881010024B106000203 +S325000166204BFF9B5981210018A0A9000070A5200060A5DC00B0A900004BFF9B41808100205C +S32500016640808400003D00000061088000B104000C4BFF9B298121002080C9002038C6000110 +S3250001666038E000047FE63BD67FFF39D67CDF305090C900208061001C480038018121002060 +S325000166804BFFFF1C7FE802A697E1FFC8808100409081001C80C400EC54C718387CC63A14A7 +S325000166A054C6103A3902A3387CC6421490C1002880A60000A0A5001090A100304BFF9ABDCB +S325000166C0808100288084000081010030B10400104BFF9AA98181001C8141002881010030C8 +S325000166E0710800154182002438629BD880AC00EC90A1000880A1003090A1000C4BFFD265B1 +S325000167008181001C8141002881010030710800094082000480AA001454A5183880CA000C93 +S325000167207D65321491610024A0AB00007CA92B7870A58000408201247128003F408200C427 +S3250001674071250C002C050C00408200B8A0AB00023865FFFC90610034480036C98161002482 +S325000167607C0300004182004C9061002080630004808B000490810008808100349081000C12 +S32500016780480067E1812100208081003480C900047C862214908900048061001C9121000812 +S325000167A0390000019101000C4BFFFBD981610024B00B0002A08B0000708420006084900066 +S325000167C0B08B00004BFF99B58181001C8141002880AA001438A5000138C000207FE533D636 +S325000167E07FFF31D67CBF285090AA001480EA001454E71838810A000C7D6742144BFFFF28C1 +S32500016800712700044182001080CC010438C6000190CC01047124000241820010810C011049 +S3250001682039080001910C01107126003F4182001438629BF44BFFD12D816100244BFFFF7480 +S32500016840712808004082FF6C38629BF64BFFD115816100244BFFFF5C80E1003070E7000273 +S32500016860418200107D8363784BFFFD0D8141002880A1003070A50010418200183860000636 +S3250001688080EA000890E100089001000C4BFFD2D183E100007FE803A6382100384E80002089 +S325000168A07FE802A697E1FFE03DA0000061AD90007C6A1B78906100248103000C7C0800004E +S325000168C04082001C386000204BFFD4213DA0000061AD900081410024906A000C80CA00101B +S325000168E07C060000408200243C6000006063BE0090010008480026253DA0000061AD900065 +S3250001690081410024906A001080AA001074A5E0003CC020007C0530004182015C808A001046 +S325000169207C8C23787C0B03782C0B0020408000445567183880AA000C7CE72A14B0070002B4 +S325000169405564183880EA000C7C843A14918400045568183880CA000C7D083214B1A80000C3 +S32500016960398C05F0396B00012C0B00204180FFC45564183880EA000C7C843A14A0C4FFF8AE +S3250001698060C62000B0C4FFF8900A001480CA00187C06000040820014386000044BFFD34DD1 +S325000169A081410024906A0018808A001C7C04000040820018386017C0900100084800255D86 +S325000169C081410024906A001C810A001C7508E0003D2020007C0848004182008880EA001C96 +S325000169E07CEC3B787C0B03782C0B00044080004855651838810A00187CA5421491850004F2 +S32500016A005564183880EA00187C843A14B004000255661838808A00187CC6221439005C00A6 +S32500016A20B1060000398C05F0396B00012C0B00044180FFC05567183880AA00187CE72A148F +S32500016A40A087FFF860842000B087FFF8900A002083E100007FE803A6382100204E8000204A +S32500016A6080EA001C3FE0FFFF63FFFFFF7FE738394BFFFF70808A00103FE0FFFF63FFFFFFE5 +S32500016A807FE420394BFFFE9C7FE802A697E1FFD080A3000454A5083C3985FFFE80A2801424 +S32500016AA08145002038A000037CAB6030A0CA09527CC75B78B0EA09527D6658F8A0AA0950B1 +S32500016AC07CA63038B0CA09507D6558F8A08A09547C852838B0AA095438E000307CEB603042 +S32500016AE07D6458F8A10A09627D042038B08A09627D6858F8A0EA09607CE84038B10A0960A2 +S32500016B00A0CA09647CC75B78B0EA0964906100348063000838E1002890E1000838810024D3 +S32500016B209081000C4BFF9BDD8061003480630004808100289081000880E1002490E1000C2F +S32500016B404BFFD0D180A1003480A5000454A5103A38C283A87CA53214806500009061001C04 +S32500016B609001000838A000A490A1000C480061C13D8020008161001C8141003438800018B1 +S32500016B80988B000438E0001898EB000538A005F0B0AB0006810A000C7508E0007C08600009 +S32500016BA04182018480CA000CB0CB000080AA001874A5E0007C05600041820158810A0018DA +S32500016BC0B10B00027C03037880AA000890A100089001000C4BFFCF8981A100388181003CB4 +S32500016BE08161001C38E0FFFF90EB00303CA0DEBB60A520E390AB0034900B0038900B003C39 +S32500016C00900B00403C80000060848888B08B004438E0000FB0EB004638A005EEB0AB004AEB +S32500016C2039000040B10B004C38C005F0B0CB004E388005F0B08B0050B00B00787C0A0378AA +S32500016C402C0A00064080003C7CEA621488E7000154E7402E7D0C5214890800007CE7437862 +S32500016C60392000027D0A4BD65508083C7D085850B0E80076394A00022C0A00064180FFCCE1 +S32500016C803900080AB10D00083CC0000060C6D555B0CD000E900D00043CC0108860C6000C9E +S32500016CA090CD00004BFF94D580E100383C8000006084FFFFB08700104BFF94C180A1003847 +S32500016CC038E0001AB0E500144BFF94B1810280148168002081010034810800043908FFFFA1 +S32500016CE0392010007D284030808B0ABC7C87437890EB0ABC80CB0AB87CC44378908B0AB85A +S32500016D0083E100007FE803A6382100304E800020810A00183FE0FFFF63FFFFFF7FE8403981 +S32500016D204BFFFEA080CA000C3FE0FFFF63FFFFFF7FE630394BFFFE747FE802A697E1FF7011 +S32500016D40906100943861008A9001000838A0000690A1000C48005FD93861008A8101009417 +S32500016D603908002C9101000838C0000690C1000C48006759812100947C030000408200909B +S32500016D8038629BF84BFFCBDD3861001C39029C11910100084800666538629C1E38C1004EE8 +S32500016DA090C10008390000329101000C38C1001C90C100104BFFCA357C0300004080001854 +S32500016DC03860FFFF83E100007FE803A6382100904E800020806100943863002C3881004E88 +S32500016DE0908100084BFFC209812100947C0300004080001C88C9002C2C0600FF418200104C +S32500016E0038629C304BFFCB5D4BFFFF8080E9001C54E7103A388280887CE7221480E70000FE +S32500016E2080C2801480C600207D663A1480C9001C54C6103A38E280307CC63A1480C6000075 +S32500016E4038C6001090C9002080E900EC54E818387CE7421454E7103A3882A3387C672214D7 +S32500016E60916100809163000080E9001C90E3000480E9001C54E7103A390283107CE7421418 +S32500016E8080E7000090E30008906100844BFFFA158061008480A1008090A1000881010094E6 +S32500016EA03908002C9101000C4BFFFBE1812100943D00FFC261086E38910900B83CE0FFC228 +S32500016EC060E7663090E900BC3CC0FFC260C6667490C900CC3CA0FFC260A5678490A900D021 +S32500016EE07C03037883E100007FE803A6382100904E8000203821FFD08161003C82810038C5 +S32500016F00824100407C751B7838A000017CAE583038A000017CA570303A65FFFF38A0000148 +S32500016F207CAA903038A000207CAF96307D4558307E2E2850388000207DAF20507C0D000010 +S32500016F40418000787C0A03787EB06C307C0C03787C0B03787C0B7800408000247E665830D2 +S32500016F607E0630387CC660307D4A33787D8C8A147D6B72147C0B78004180FFE47C0B037820 +S32500016F807C0B90004080001C7DC758307D4738307D4A3B78396B00017C0B90004180FFEC1D +S32500016FA07E88A3783A940004914800007DAF68507C0D00004080FF90382100304E800020CB +S32500016FC07FE802A697E1FEF89061010C3861010C480006498141011880C101248081011C93 +S32500016FE07CC430514181001483E100007FE803A6382101084E8000208081012880E1012083 +S325000170007C8720503884FFFF908100FC80A100FC7C0500004080001483E100007FE803A649 +S32500017020382101084E80002080E1010C81A7000C808101107C87683090E1011091A100F402 +S325000170407CCB6830836A000C8081011C7C87D83090E1011C936100F8808101247C87D8307D +S3250001706090E1012480E1010C83470008832A000880E10114934100E87CE7D1D680A1010C14 +S3250001708080A500047CE72A14808101107C842E707CE43A1454E7103A80C1010C80C60000A8 +S325000170A07EE7321492E100CC80C10120932100EC7CC6C9D6808A00047CC622148101011CD7 +S325000170C07D082E707CC8321454C6103A80AA00007EC62A1492C100D080A1011070AC001F5C +S325000170E03900FFFF7D086430910100B0918100DC7D0C5A147108001F38A000207D08285085 +S3250001710038C0FFFF7CC840303FE0FFFF63FFFFFF7FE84039910100AC810100AC7C08000071 +S325000171204082000C38A0FFFF90A100AC80C1011C70C6001F90C100E4810101107C8B4214EF +S325000171403884FFFF7C842E7080A101107CA52E707C8520509081010080A1010C7C0A280080 +S325000171604082005880E10120808101147C0720004080046080C100FC7CC6D1D654C6103A05 +S325000171807EF73214808100FC7C84C9D65484103A7ED6221480EA000854E7083C7F27C85036 +S325000171A0932100EC8081010C808400085484083C7F44D050934100E8808101007C040000D1 +S325000171C04082001480C100AC810100B07D06303890C100B080C1012C70C6000F90C1012C96 +S325000171E07E9B68507D85A63080C100E47E6530507C1803787C1300004080000C3B000001B1 +S325000172007E7300507C1003787C15037892A100A480A100FC7C152800418100F892E100CC6D +S325000172207EECBB7892E100C492C100D07ECFB37881A100B091A100C07C0E03787C1800007B +S32500017240408200107DE57B7839EF000481C500007C12037882210100922100A87C110000F9 +S325000172604180008C7C1200004182027C7E0783783A10000481670000814C00008101012CB9 +S325000172802C08000841810194418201702C08000441810110418200F87C080000418200D83B +S325000172A02C080001418200B02C080002418200942C0800034182006C398C0004918100C48D +S325000172C039A0FFFF91A100C02C1100014082000C81A100AC91A100C03A52FFFF3A31FFFF1F +S325000172E0922100A87C1100004080FF7C5727103A7ED63A145747103A7EF73A143AB500015F +S3250001730092A100A480A100FC7C1528004081FF1083E100007FE803A6382101084E80002025 +S325000173203FE0FFFF63FFFFFF7FE65A787CC652787CC668387D46327890CC00004BFFFF7C16 +S325000173407D6750387CE768387D473A7890EC00004BFFFF683FE0FFFF63FFFFFF7FE85A785E +S325000173607D0853787D0868387D484278910C00004BFFFF483FE0FFFF63FFFFFF7FE56A7821 +S325000173807D45283890AC00004BFFFF307D6553787CA568387D452A7890AC00004BFFFF1C9C +S325000173A02C080005418200482C080006418200302C080007418200084BFFFF003FE0FFFFE9 +S325000173C063FFFFFF7FE852787D6843787D0868387D484278910C00004BFFFEE07D67683888 +S325000173E07D473A7890EC00004BFFFED07D446A78908C00004BFFFEC43FE0FFFF63FFFFFF34 +S325000174007FE75A787CE750387CE768387D473A7890EC00004BFFFEA42C08000C41810070EF +S32500017420418200582C080009418200342C08000A4182FE882C08000B418200084BFFFE7CA1 +S325000174403FE0FFFF63FFFFFF7FE75A787CE768387D473B7890EC00004BFFFE603FE0FFFFB5 +S3250001746063FFFFFF7FE65A787CC668387D46327890CC00004BFFFE447D6852787D08683863 +S325000174807D484278910C00004BFFFE302C08000D418200342C08000E4182001C2C08000FB5 +S325000174A0418200084BFFFE147D476B7890EC00004BFFFE087D6668387D46337890CC0000DE +S325000174C04BFFFDF87D6750383FE0FFFF63FFFFFF7FE73A787CE768387D473A7890EC000070 +S325000174E04BFFFDD8930100D47C180000418200AC38E000207CF338507DC738307DE57B78CB +S3250001750039EF000491E100C881C5000091C100BC926100D87DC89C307CEB437838E0000193 +S325000175207CF2A0309241001C2C1400014180FD4C7D635B7838A1002490A100089361000CE3 +S32500017540928100F0928100104BFFF9AD836100F8834100E8832100EC830100D482E100CC6F +S3250001756082C100D082A100A4828100F0826100D88241001C822100A881E100C881C100BC2A +S3250001758081A100C0818100C4390100243A080004816800004BFFFCE47DCB98307DE77B781E +S325000175A039EF000491E100C881C7000091C100BC926100D87C1300004182FF6438E0002050 +S325000175C07CF338507DC73C307D6B3B784BFFFF5080C10120810101147C0640004082FBDC75 +S325000175E080A1011C80E101107C053800418000084BFFFBC84800600181A100F4836100F8AA +S32500017600834100E8832100EC818100DC82E100CC82C100D04BFFFBA43821FFE87C691B7866 +S3250001762080E30018810300107D68385080E3001C810300147D48385080E3000480C30000B9 +S3250001764080C600207C0730004080003080E9000080E70020808900047CE43850810900109B +S325000176607CC83A1490C9001080A900047D053A14910900047D6758508109000880E90000E6 +S3250001768080E700247C08380040800030810900008108002480A900087D0540508089001415 +S325000176A07CE4421490E9001480C900087C864214908900087D485050808900047C845A14D6 +S325000176C080C9000080C600287C0430004081002480E900047CEB3A1480A9000080A50028BF +S325000176E07CE53850810900187CE7405090E9001880C900087CC65214810900008108002C3C +S325000177007C06400040810024808900087C8A221480E9000080E7002C7C87205080A9001CBA +S325000177207C8428509089001C8109001080E9000C80E700207C0838004080002C8109000CC1 +S325000177408108002080A900107D054050808900047CE4421490E9000480C900107C8642143D +S3250001776090890010808900148109000C810800247C0440004080002C8089000C8084002490 +S3250001778080C900147C86205080A900087D0522149109000880E900147CA7221490A9001465 +S325000177A080A900188089000C808400287C0520004081001080E9000C80E7002890E9001839 +S325000177C08089001C8109000C8108002C7C0440004081001080C9000C80C6002C90C9001C65 +S325000177E0382100184E8000203821FFF0814100187C691B787C070378394AFFFF7C0A000084 +S32500017800418000207D244B7839290001888400007CE72214394AFFFF7C0A00004080FFE866 +S325000178207CE33B78382100104E80002081210008390227107C0940404081000C7C0918400D +S325000178404180000C7C0303784E800020386000014E8000207FE802A697E1FFE080C3000438 +S3250001786038A0FFFF7C0628004182001480C300043CA000047C062840418000187C030378C6 +S3250001788083E100007FE803A6382100204E80002088C3000B2C0600FF4182FFE480E3000472 +S325000178A0810282F87D683A14906100249161001C916100084BFFFF79816100247C0300002D +S325000178C0408200187C03037883E100007FE803A6382100204E80002088AB000854A5402E50 +S325000178E0890B00097CA5437854A5402E888B000A7CAA23783D0000FF6108FFFF7C0A40005A +S32500017900408200087C0A03787C0A0000408000187C03037883E100007FE803A63821002050 +S325000179204E8000207C0A0000408100307D635B78914100188121001C7CAA4A1438A5FFFF21 +S3250001794090A100084BFFFEE981610024814100187C0300004182007C80CB000038A0FFFFF7 +S325000179607C062800418200288061001C91410018914100084BFFFE758141001880E100248E +S3250001798080E700007C0338004082002C80A1002880E1001C90E500008081002C9144000097 +S325000179A03860000183E100007FE803A6382100204E80002038628CD04BFFBFA97C030378AA +S325000179C083E100007FE803A6382100204E8000207C03037883E100007FE803A638210020DE +S325000179E04E8000207FE802A697E1FFB8900282F890028300900282FC386100203881003879 +S32500017A009081000838C1003490C1000C4BFF8C157C0300004080002038628CE54BFFBF4519 +S32500017A207C03037883E100007FE803A6382100484E80002081010034910282FC80A1003822 +S32500017A4090A282F880E282F83CE7000490E28300900283049002830880A282F83FE0000387 +S32500017A6063FFFFF07D3F2A149121003C3869000C390282F09101000838A0000490A1000CB9 +S32500017A8048005A497C030000408200A080E1003C88E7000B2C070002408200248061003CC4 +S32500017AA038A1004090A1000838E1004490E1000C4BFFFDA57C030000408200108101003C98 +S32500017AC03928FFF04BFFFFA4808100442C04000B408000108101003C3928FFF04BFFFF8C2F +S32500017AE080610040390280C09101000838A0000B90A1000C480059D57C0300004182001061 +S32500017B008101003C3928FFF04BFFFF6080E1004090E2830480810044908283088101003C6D +S32500017B203928FFF04BFFFF4480A283047C050000408200B438628D504BFFBE2980628300B4 +S32500017B404800356D2C0306EB4082002038628D804BFFBE113860000183E100007FE803A665 +S32500017B60382100484E80002081028300890800005508402E80C2830088C600017D083378C9 +S32500017B805508801E80E2830088E7000254E7402E80828300888400037CE723787D083B781A +S32500017BA02C0806EB4082002038628DAA4BFFBDB53860000183E100007FE803A6382100487C +S32500017BC04E8000209002830038628DD64BFFBD957C03037883E100007FE803A638210048F3 +S32500017BE04E80002038628D6280E2830490E1000880A2830890A1000C81028304910100100F +S32500017C004BFFBD614BFFFF38806283044E8000207FE802A697E1FFF080C283007C06000060 +S32500017C204182006880628300480034857C0300004082004480A2830088A5000054A5402EEE +S32500017C4081028300890800017CA5437854A5801E80828300888400025484402E80C2830074 +S32500017C6088C600037C8433787CA523782C0506EB408200183860000183E100007FE803A63C +S32500017C80382100104E8000207C03037883E100007FE803A6382100104E8000207FE802A6B2 +S32500017CA097E1FFB080E283007C070000408200183860FFFF83E100007FE803A638210050A1 +S32500017CC04E8000208142830088CA000054C6402E888A00017CC6237854C6801E88AA0002B3 +S32500017CE054A5402E88EA00037CA53B787CC62B782C0606EB408202387D49537888CA0014D2 +S32500017D0054C6402E888A00157CC6237854C6801E88EA001654E7402E890A00177CE743781F +S32500017D207CC63B7874C6E0003D0020007C064000418201C488A9001454A5402E88C9001574 +S32500017D407CA5337854A5801E88E9001654E7402E888900177CE723787CA53B7890A1004C12 +S32500017D60398A00208161004C88E9000454E7402E88A900057CE72B7854E7801E88C9000661 +S32500017D8054C6402E91210040890900077CC643787CEA33787C0B6000418200507D635B780E +S32500017DA0916100489181002091810008914100249141000C480051AD38628DF980C1004873 +S32500017DC090C10008808100209081000C80E1002490E100104BFFBB8D818100208161004821 +S32500017DE081410024812100407D8C521480A1004C3CE0FFC07C053840418000E439403000B6 +S32500017E0088A9000854A5402E890900097CA5437854A5801E8889000A5484402E88C9000BF0 +S32500017E207C8433787CA523787D43537891410048918100209181000890A1002490A1000C51 +S32500017E404800512138628E1980A1004890A10008810100209101000C80C1002490C1001078 +S32500017E604BFFBB0138628E398081004C908100084BFFBAF14BFF91CD4BFFBDED8101004CCF +S32500017E807508E0003CA020007C0828004182002480E1004C7CE803A64E8000213860FFFFB0 +S32500017EA083E100007FE803A6382100504E80002080E1004C3FE0FFFF63FFFFFF7FE73839AF +S32500017EC07CE803A64E8000213860FFFF83E100007FE803A6382100504E8000207C8A5A148A +S32500017EE038840FFF3FE0FFFF63FFF0007FEA20394BFFFF1088AA001454A5402E88EA0015F3 +S32500017F007CA53B7854A5801E890A00165508402E88CA00177D0833787CA543783FE0FFFFE9 +S32500017F2063FFFFFF7FE528394BFFFE349141003480C1003490C100283D0A000C9101003090 +S32500017F4080C1003090C1002C386100283881004C90810008480032057C0300004080FF0888 +S32500017F603860FFFF83E100007FE803A6382100504E8000207FE802A697E1FF907C691B78CB +S32500017F803861003491210008480054713861003438C1002490C10008390000049101000C28 +S32500017FA038C29AD590C1001048000D9D2C030002418201482C030003418200187C030378BA +S32500017FC083E100007FE803A6382100704E8000208101007C9008000039429E0080AA000492 +S32500017FE07C050000418201007C0903782C090003408000E45524103A7C8452148084001C10 +S325000180007C040000418200C4806100249121001C5528103A9141006C7D0852148108001CEA +S32500018020910100084800543D8141006C8121001C7C0300004082009480C10078810A0000C1 +S32500018040910600008101007C38A000017CA54830808800007C852B7890A800008061002825 +S3250001806038A1002090A100089001000C48004EF981010080906800007C030000408200144C +S3250001808080A1002080E100287C053800418200288061008480A1002C90A100084800535D88 +S325000180A03860000183E100007FE803A6382100704E8000207C03037883E100007FE803A687 +S325000180C0382100704E800020392900012C0900034180FF24394A003080AA00047C05000001 +S325000180E04082FF087C03037883E100007FE803A6382100704E80002039029AD79101002C21 +S325000181004BFFFED07FE802A697E1FF30906100D47C0303784BFF8E39814100D8812100D4AA +S3250001812071440004418200503C60001F6063FF6A38C29AD890C10008810900008108002489 +S325000181409101000C80A9000C90A100104BFFB7D1806100D48063000C810100DC9101000896 +S325000181604BFFA29183E100007FE803A6382100D04E800020714600084182002881090004B8 +S32500018180710800084182001C7C0303784BFFFA85814100D8812100D47C03000040820274EE +S325000181A071460002418200FC8109000471080010418200348069000C38A29ADE90A10008B2 +S325000181C080E9000080E700187CE803A64E800021806100D43863000C900100084BFFAB6169 +S325000181E0812100D4808100DC7C040000418200A480C100DC88C600007CC607747C06000094 +S32500018200418200908069000C80A100DC90A1000881090000810800187D0803A64E80002191 +S32500018220812100D43C60001F6063FF6A38829AE39081000880C9000080C6002090C1000C7E +S325000182408109000C91010010810100DC910100144BFFB6CD812100D48069000C80A9001466 +S3250001826090A1000880A9001090A1000C480017A5906100247C0303784BFF8CD58061002485 +S3250001828083E100007FE803A6382100D04E80002080E9000838E7000890E100DC4BFFFF68B6 +S325000182A0714700014182015880890000808400187C040000418200248069000C39029AECA0 +S325000182C09101000880A9000080A500187CA803A64E800021812100D480C9000470C60010D2 +S325000182E0418200103869000C900100084BFFAA5180C100DC7C06000041820084810100DCD5 +S32500018300890800007D0807747C080000418200703861002C810100DC91010008480050DDDC +S325000183203C60001F6063FF6A38C29AF690C10008810100D4810800008108001C9101000C4A +S3250001834080A100D480A5000C90A1001038A1002C90A100144BFFB5C9806100D43863000C41 +S325000183603901002C910100084BFFD56983E100007FE803A6382100D04E8000203861002C1E +S32500018380808280A080840000908100084800506D3861002C38C0002F90C1000848004F3D79 +S325000183A07C03000041820050392300017D234B7838A29AF190A1000848005041806100D438 +S325000183C03863000C3881002C9081000838C100AC90C1000C4BFFD4417C0300004181FF440C +S325000183E03860FFFF83E100007FE803A6382100D04E8000203921002C4BFFFFB43860FFFF3C +S3250001840083E100007FE803A6382100D04E8000208069000C4BFFF889814100D8812100D4FA +S325000184204BFFFD803821FFF08142801838C2E53838C608007C0A3040418000107C030378ED +S32500018440382100104E8000203923002C80E900007C0700004182001880E900003927007C2A +S3250001846080E900007C0700004082FFF038EA008090E2801891490000806900003821001080 +S325000184804E8000207FE802A697E1FFA89061005C39629E00810B00047C080000418200302C +S325000184A080E1005C2C07FFFF41820038808B00008101005C7C08200041820028396B003080 +S325000184C0810B00047C0800004082FFD87C03037883E100007FE803A6382100584E800020DB +S325000184E080AB000C7C0500004182FFD4808100607C0400004182005C814B002C7C0A0000A9 +S3250001850041820050810A0004812100607D2840394182003480A100642C05FFFF4182001410 +S3250001852080EA000C80C100647C063800408200187D43537883E100007FE803A638210058D5 +S325000185404E800020814A007C7C0A00004082FFB8808B0008708400804082002880AB00083C +S3250001856060A5008090AB000891610054808B000C7C8803A64E80002181610054906B0028DA +S325000185807C0D0378808B00287C0400004182FF30810B0028392000017D2968307D084839D9 +S325000185A04082000C39AD00014BFFFFDC3880000191A1004C7C8468307C8420F8810B00283F +S325000185C07D042038908B00287D635B78916100544BFFFE5581A1004C816100547C6A1B78C5 +S325000185E07C0300004082000C39AD00014BFFFF9891A3000C80CB000890C30004810B0014D5 +S325000186009103001480AB001090A300109163000090610044808300047084000241820078CC +S325000186207DA36B7838C29AFF90C10008812B00187D2803A64E80002181A1004C816100549F +S3250001864081410044906A00087C0300004082001880EA00043FE0FFFF63FFFFFD7FE73839F2 +S3250001866090EA000480AA000470A50018408200287DA36B7838A29B0490A1000880EB0018F8 +S325000186807CE803A64E80002181A1004C816100548141004480CA000470C60001418200B82D +S325000186A09001004838A0000190A1005080CA000080C600187C0600004182005C7DA36B7834 +S325000186C038A29B0990A10008810A0000810800187D0803A64E8000217C0300004182001839 +S325000186E080830000908100487C04000041820008900100508061004C38C29B0D90C10008C3 +S3250001870081010054810800187D0803A64E80002181410044386A000C8081004890810008A8 +S32500018720810100509101000C4BFFC96181A1004C81610054814100447C030000408000DC89 +S3250001874080EA00043FE0FFFF63FFFFEE7FE7383990EA000480AA000470A50010418200705D +S3250001876080CA00043FE0FFFF63FFFFEF7FE6303990CA0004398282B8918280A0808C0000D7 +S325000187807C04000041820048386A000C80AC000090A1000838A1002090A1000C4BFFD0796B +S325000187A081A1004C81610054814100447C0300004181005880C280A039860004918280A017 +S325000187C0808C00007C0400004082FFC080EA0004810100607D0738394182FDCC808100644F +S325000187E02C04FFFF4182001080C100647C0668004082FDB47D43537883E100007FE803A670 +S32500018800382100584E800020808A000460840010908A00044BFFFFB838629B124BFFB1450A +S3250001882081A1004C81610054814100444BFFFF287FE802A697E1FEF8480004C14BFF7AA127 +S32500018840480006654BFFB2394800254D4BFFAD1D4BFF7B314BFF8F614BFFA2E938629B23FE +S325000188604BFFB101900280B44BFF791D38629B2C4BFFB0F14BFF7D657C6A1B7838629B32F7 +S32500018880914100E8914100084BFFB0D97C0B037839429E0080CA00047C060000418200209C +S325000188A080AA00002C050002408203FC394A003080CA00047C0600004082FFE87C0B0000E0 +S325000188C0418203C480CB000470C60010418203B880A100E870A50002408200147C03037804 +S325000188E04BFFF3317C03000040820388900100F0900100F438629B4C4BFFA3B990610024F5 +S32500018900900100FC80A100247C0500004182005838E0000290E100F47C0A03782C0A000329 +S32500018920408002BC80610024914100F855451838388283487CA5221480A5000090A10008BF +S3250001894048004B21814100F87C030000408202845547183838C283487CE7321480E7000416 +S3250001896090E100F4808100F07C0400004082001080C100F42C060002408201D4980100B0FF +S325000189803860FFFF9001000838C0FFFF90C1000C4BFFFAF5900100FC39029E0091010020FD +S325000189A081010020810800047C080000418200D480E100208147002C914101047C0A000094 +S325000189C0418200A4808100FC7C0400004082001838C0000190C100FC38629B884BFFAF8551 +S325000189E08141010480EA000470E700044182002438629B9680CA000080C6002490C1000821 +S32500018A00810A000C9101000C4BFFAF5981410104810A0004710800014182002438629B9D3F +S32500018A2080EA000080E7001C90E10008808A000C9081000C4BFFAF2D81410104808A00049B +S32500018A4070840018408200E4810A000471080002408200D8814A007C914101047C0A000015 +S32500018A604082FF6480A1002038A5003090A1002081010020810800047C0800004082FF3483 +S32500018A80808100FC7C0400004182000C38629BAB4BFFAED138629BAD38E1002890E100083E +S32500018AA0388000509081000C38E100B090E100104BFFAD397C0300004180006838610028A7 +S32500018AC0388100EC9081000838C100FC90C1000C392101009121001038A1007890A10014CC +S32500018AE04BFFF4957C03000041820038806100EC80A100FC90A10008810101009101000CDE +S32500018B004BFFF9857C03000041820018810100FC9101000838C1007890C1000C4BFFF5E91E +S32500018B20980100B04BFFFF7038629BA480EA000080E7002090E10008808A000C9081000CB6 +S32500018B404BFFAE21814101044BFFFF0C3900001F910100FC808100F42C04000140820018F3 +S32500018B6080C100FC3FE0FFFF63FFFFFB7FE6303990C100FC808100E8708400024182001863 +S32500018B8080C100FC3FE0FFFF63FFFFF77FE6303990C100FC3860FFFF80C100FC90C10008D5 +S32500018BA038A0FFFF90A1000C4BFFF8DD7C0300004182FDCC81030004812100FC7D2840382E +S32500018BC0910100089001000C4BFFF53D4BFFFDB0394A00012C0A00034180FD4C8061002418 +S32500018BE038C100EC90C10008390100FC9101000C38A1010090A1001038E1007890E100142B +S32500018C004BFFF3757C0300004082001838629B5580810024908100084BFFAD494BFFFD48AB +S32500018C20806100EC808100FC90810008810101009101000C4BFFF8517C030000408200183D +S32500018C4038629B6E81010024910100084BFFAD154BFFFD14810100FC9101000838E100781A +S32500018C6090E1000C4BFFF4A1906100F04BFFFCF838629B404BFFACED7C0303784BFFF021C5 +S32500018C804BFFFC6C7C0303784BFFEF81906100187C03037880E1001890E100084BFFA0A1E7 +S32500018CA04BFFFC3091410020806A000038A0001090A1000838C0FFFF90C1000C4BFFF7C9DD +S32500018CC0814100207C6B1B787C0300004182FBE0808B000470840010408200084BFFFBD022 +S32500018CE091610104386B000C900100084BFFA051816101044BFFFBC87FE802A697E1FFE891 +S32500018D008062801490010008388000249081000C4800401D80C2801439004E209106000487 +S32500018D204BFF74C180E28014906700103CA0FA2090A7002083E100007FE803A6382100187E +S32500018D404E8000207FE802A697E1FFE87C691B78900100147C0900004182001488E90000C6 +S32500018D607CE707747C070000408200188061001483E100007FE803A6382100184E800020E9 +S32500018D8080C10014810100247C064000418000188061001483E100007FE803A6382100185C +S32500018DA04E80002088A900007CA507747C05000041820028806100289121001C88C900005D +S32500018DC07CC6077490C1000848003F418121001C7C030000408200C0890900007D0807745D +S32500018DE07C080000408200188061001483E100007FE803A6382100184E8000208081001431 +S32500018E005484103A80E100207C843A149124000088C900007CC607747C060000418200282A +S32500018E20806100289121001C88E900007CE7077490E1000848003ED58121001C7C030000F4 +S32500018E404182001480E1001438E7000190E100144BFFFF04888900007C8407742C04005CB5 +S32500018E604082001488A900017CA507742C05000A4182000C392900014BFFFF987D264B7893 +S32500018E803929000138E0002098E60000392900014BFFFF807D284B7839290001980800001B +S32500018EA04BFFFF047FE802A697E1FFE03862813838C2C7D090C10008390010009101000CD4 +S32500018EC04800125538C2271074C6E0003CE020007C0638004182003038A227103862813844 +S32500018EE090A100083CE000407CE5385090E1000C4800124983E100007FE803A638210020E0 +S32500018F004E80002038A227103FE0FFFF63FFFFFF7FE528394BFFFFC87FE802A697E1FFD89A +S32500018F209061002C810100307C0800004181000C38A0000490A100304BFF72699061002096 +S32500018F4038628138900100088081002C9081000C80E1003090E10010480013499061002409 +S32500018F60806100204BFF725980E100247C0700004082000C38629BC74BFFAA718061002498 +S32500018F809001000880A1002C90A1000C48003DA183E100007FE803A6382100284E8000209E +S32500018FA07FE802A697E1FFE8388300033FE0FFFF63FFFFFC7FE42039386400089061001C97 +S32500018FC038800004908100084BFFFF5138A300043D00CAFE6108BEEF9103000038650004EC +S32500018FE08121001C9125000083E100007FE803A6382100184E8000207FE802A697E1FFE0BD +S325000190007C0300004182005038C3FFF890C1001880C600003CE0CAFE60E7BEEF7C06380084 +S325000190204182000C38629BCE4BFFA9C14BFF7175812100189061001C38628138912100089F +S32500019040810900049101000C480010F18061001C4BFF716D83E100007FE803A63821002082 +S325000190604E8000204E8000207FE802A697E1FFF0808283809081000C390000FF9904001090 +S325000190804BFF70F98081000C88C4000060C6000198C400004BFF70E58081000C38C000177F +S325000190A098C400144BFF70D583E100007FE803A6382100104E8000203821FFF080E2838032 +S325000190C09807001489070000710800FE99070000382100104E8000207FE802A697E1FFC092 +S325000190E038C2837090C100308106000C7C0800004182001483E100007FE803A63821004000 +S325000191004E800020386283C84BFFA8598141003038800001908A000C3CA0FA2060A50860F6 +S3250001912090A1003890AA00103CA0FA2060A53C8090AA00144BFFFF858121003080A9002C7B +S325000191407C050000408200283860008438A0000290A100084BFFFDC5812100309069002C6B +S3250001916080E9002C38E7008490E9002880E900307C0700004082001C3860008438E00002DF +S3250001918090E100084BFFFD95812100309069003080E900187C0700004082004838600001D1 +S325000191A04BFFAB49812100309069001880C9003074C6E0003CE020007C06380041820248F1 +S325000191C080A9003080E9001890A7000480E90018B007000280C9001838A02000B0A600008A +S325000191E080C9001C7C06000040820048386000024BFFAAF9812100309069001C80A9002CB4 +S3250001920074A5E0003CC020007C053000418201E48089002C80C9001C9086000480C9001CC0 +S32500019220B006000280A9001C38802800B085000080A280148145002080EA0AB860E70030D6 +S3250001924090EA0AB8A0EA0AC260E70030B0EA0AC280EA0ABC60E7003090EA0ABC81490014D3 +S3250001926080E9001874E7E0003CC020007C0730004182016C80A90018B0AA00008089001C6C +S325000192807484E0003D0020007C0440004182013C80E9001CB0EA000238C0001898CA00043B +S325000192A038800018988A000538E00084B0EA0006900A0008900A000CA08A0000B08A0010B8 +S325000192C0B00A0012900A0018A0AA0002B0AA0020900A001CB00A00224BFF6EA181E2801461 +S325000192E03DC0000161CE86A08181003838C0000198CC000C980C0000980C00047DCD7378F0 +S3250001930080EF00087CE773D6388000027CE723D63A07FFFD7C0B03787C0B80004080008087 +S32500019320394000037C0A000041800068808F000838AA00027C842E305567083C38E700067D +S325000193407C843BD67D247051408000087D2900507C096800408000307D2D4B78996C00087E +S3250001936088AC00003FE0FFFF63FFFFF97FE52839390000037D0A40505508083C7CA54378A6 +S3250001938098AC0000394AFFFF7C0A00004080FFA0396B00017C0B80004180FF883860002070 +S325000193A03CC0FFC260C6951890C10008390283709101000C480018BD83E100007FE803A660 +S325000193C0382100404E80002080E9001C3FE0FFFF63FFFFFF7FE738394BFFFEBC80A90018E1 +S325000193E03FE0FFFF63FFFFFF7FE528394BFFFE8C8089002C3FE0FFFF63FFFFFF7FE42039E2 +S325000194004BFFFE1480A900303FE0FFFF63FFFFFF7FE528394BFFFDB07FE802A697E1FFE0F1 +S3250001942080A1002890A10018812500109121001488E9001090E1001C4BFF6D418141001837 +S325000194408121001C80810014992400107126001441820034386283D6912100084BFFA50522 +S325000194608121001880C900207C060000418200089009002083E100007FE803A638210020CF +S325000194804E8000207127000241820018808A00202C0400034082000C38A0000190AA002004 +S325000194A0712600014182FFD0810A00202C0800044082FFC438800001908A002083E10000BC +S325000194C07FE803A6382100204E800020806300202C0300024080000C386000014E80002087 +S325000194E07C0303784E8000207FE802A697E1FFE89061001C80C1001C900600249001001446 +S325000195008061001C4BFFFFC97C0300004082007480A280B47C0500004182FFE880E100148A +S3250001952038E7000190E100142C0700644081002C80C1001C39000001910600208081001C90 +S3250001954038C0000190C4002483E100007FE803A6382100184E800020386000014BFF952127 +S325000195607C03037880E1001C90E100084BFFFEAD8061001C4BFFFF597C0300004182FF948B +S3250001958083E100007FE803A6382100184E8000207FE802A697E1FFD88181003439628370CF +S325000195A02C0C0080408100183860FFFF83E100007FE803A6382100284E8000203940000120 +S325000195C080CB002C3FE0FFFF63FFFFFE7FE5183998A60000706500014182001480EB002C5A +S325000195E07C66467098C70001394A000191610024806B002C914100207C63521480A1003033 +S3250001960090A100089181000C48003959812100243900000391090020808900183D000000F8 +S325000196206108B000B104000080A9002C74A5E0003CC020007C053000418200C88089002C7A +S3250001964080C9001C9086000480C9001C80A10034808100207CA52214B0A600028109001C54 +S325000196603CE0000060E7B800B0E800004BFFF9FD810100248108001038E0008198E8000C8C +S325000196804BFF6AF9806100244BFFFE614BFFFA2D81610024814B0020808B001CA0840000BA +S325000196A0708880004082000C70850007418200183860FFFF83E100007FE803A638210028FB +S325000196C04E8000202C0A0001418200183860FFFF83E100007FE803A6382100284E8000200A +S325000196E0808B00247C0400004082FFC88061003483E100007FE803A6382100284E80002033 +S325000197008089002C3FE0FFFF63FFFFFF7FE420394BFFFF307FE802A697E1FFD081E1003C67 +S325000197203DC020007C6C1B78394283702C0F0080408100183860FFFF83E100007FE803A67E +S32500019740382100304E800020808A002C6068000199040000706800014182002480AA0028DD +S325000197603FE0FFFF63FFFFFE7FE4603998850000808A00287D8846709904000138A00004E6 +S3250001978090AA002080EA003074E7E0007C077000418201D080CA0030810A001890C8000493 +S325000197A0810A00183CE0000060E7B000B0E800007C0D0378816A001CB00B0008718500018F +S325000197C04182002C810A00287508E0007C0870004182017C80EA002890EB00043880000284 +S325000197E0B08B0002396B000839A0040080AA002C74A5E0007C0570004182013C9141002C5E +S32500019800808A002C908B000438CF0001B0CB000261A8A800B10B000091A100207C0D00001F +S325000198204182001480AA001C3C80000060848000B08500004BFFF83580A1002C80A50010B6 +S32500019840388000819885000C4BFF69318061002C4BFFFC994BFFF86581C1003C8141002CBC +S3250001986081AA0020816A001CA16B000080A100207C0500004182001080EA001CA0E70008D9 +S325000198807D6B3B78818A0018A18C00027C0C7000408100087DCC7378716800074082000C31 +S325000198A071658000418200183860FFFF83E100007FE803A6382100304E8000202C0D0001B5 +S325000198C0418200183860FFFF83E100007FE803A6382100304E800020808A0018A0840000DF +S325000198E070848000418200183860FFFF83E100007FE803A6382100304E80002080EA002403 +S325000199007C0700004082FFA48061003880EA003090E10008918100189181000C4800364521 +S325000199208061001883E100007FE803A6382100304E8000209141002C808A002C3FE0FFFFEB +S3250001994063FFFFFF7FE420394BFFFEBC80EA00283FE0FFFF63FFFFFF7FE738394BFFFE7C36 +S3250001996080CA00303FE0FFFF63FFFFFF7FE630394BFFFE287FE802A697E1FFD88161003437 +S325000199809061002C80A1003890A100247C0A03787C0A58004080004C392020007CEA585083 +S325000199A07C074800408000087D2A58508061002C80E100249141001C7CE7521490E10008FC +S325000199C09121000C80C100307CC803A64E8000218141001C906100207C030000418100182D +S325000199E07D43537883E100007FE803A6382100284E800020386285574BFF9F698161003414 +S32500019A0080E100208081001C7D443A144BFFFF847FE802A697E1FFD09061003490010008B1 +S32500019A2080A100387CA803A64E8000217C030000408000183860FFFF83E100007FE803A6A9 +S32500019A40382100304E80002038600020900100084BFFF4C97C6B1B783880002080610034C9 +S32500019A6080E1003C90E100089081002C9081000C91610020916100104BFFFEFD8141002034 +S32500019A8080C1002C7C03300041820020806282CC4BFF9ED13860FFFF83E100007FE803A6CD +S32500019AA0382100304E800020888A00005484402E88EA00017C843B785484801E890A00029F +S32500019AC05508402E88AA00037D082B787C8443782C0406EB4182004C3862855988CA0000A2 +S32500019AE054C6402E888A00017CC6237854C6801E88AA000254A5402E88EA00037CA53B784B +S32500019B007CC62B7890C100084BFF9E593860FFFF83E100007FE803A6382100304E8000203E +S32500019B2088AA001454A5402E890A00157CA5437854A5801E88CA001654C6402E88EA0017DD +S32500019B407CC63B787CA5337874A5E0003CE020007C05380041820294888A00145484402E8A +S32500019B6088AA00157C842B785484801E88CA001654C6402E890A00177CC643787C8433783C +S32500019B809081002888CA000454C6402E888A00057CC6237854C6801E88AA000654A5402E5C +S32500019BA088EA00077CA53B787CC62B783862858490C1002C90C100084BFF9DA9806100344E +S32500019BC08081003C908100088101002C9101000C80A1002890A100104BFFFD9D8161002C60 +S32500019BE0814100207C03580041820020806282CC4BFF9D713860FFFF83E100007FE803A630 +S32500019C00382100304E800020808100287CCB221438C60FFF3FE0FFFF63FFF0007FEB3039D2 +S32500019C2088EA000854E7402E88AA00097CE72B7854E7801E88CA000A54C6402E890A000B5E +S32500019C407CC643787CE733783862858790E1002C90E10008916100289161000C4BFF9D0532 +S32500019C60806100348101003C9101000880E1002C90E1000C80810028908100104BFFFCF9DD +S32500019C808141002080E1002C7C03380041820020806282CC4BFF9CCD3860FFFF83E10000D7 +S32500019CA07FE803A6382100304E8000203862859388AA000C54A5402E890A000D7CA5437843 +S32500019CC054A5801E888A000E5484402E88CA000F7C8433787CA5237890A10008890A0014D8 +S32500019CE05508402E88CA00157D0833785508801E88EA001654E7402E888A00177CE72378A8 +S32500019D007D083B789101000C4BFF9C594BFF73354BFF9F554BFF648D8141002088EA001454 +S32500019D2054E7402E88AA00157CE72B7854E7801E890A00165508402E892A00177D084B78C7 +S32500019D407CE7437874E7E0003C8020007C0720004182004888CA001454C6402E88EA0015A4 +S32500019D607CC63B7854C6801E890A00165508402E88AA00177D082B787CC643787CC803A660 +S32500019D804E8000217C03037883E100007FE803A6382100304E80002088CA001454C6402EFA +S32500019DA0890A00157CC6437854C6801E888A00165484402E88EA00177C843B787CC62378B8 +S32500019DC03FE0FFFF63FFFFFF7FE630397CC803A64E8000217C03037883E100007FE803A6E7 +S32500019DE0382100304E800020888A00145484402E88CA00157C8433785484801E88EA001669 +S32500019E0054E7402E88AA00177CE72B787C843B783FE0FFFF63FFFFFF7FE420394BFFFD64AC +S32500019E207FE802A697E1FFE89061001C386300184BFFF17138A3001890A3000C8103000C7F +S32500019E40910300049103000080C3000C80E1001C7CC63A1490C30008900300103D00CAFE70 +S32500019E606108BEE09103001483E100007FE803A6382100184E8000207FE802A697E1FFF0E3 +S32500019E807C691B787C0300004182004090610014810300143CE0CAFE60E7BEE07C0838009F +S32500019EA041820010386281284BFF9B4181210014900900143CE0DEAD60E7BABE90E900100D +S32500019EC07D234B784BFFF13583E100007FE803A6382100104E8000207FE802A697E1FFE86F +S32500019EE0386000144BFFF0BD900300049003000080A1002490A30008808100289083000CC6 +S32500019F009003001083E100007FE803A6382100184E8000207FE802A697E1FFE89061001C49 +S32500019F204BFF62818141001C90610014812A0000912100107C0900004182003C80A90010E0 +S32500019F4090AA00009009001080E90004810900007CE83850810A00107CE7405090EA00101C +S32500019F6080CA00107C0600004080000C3862812E4BFF9A79806100144BFF624580610010B5 +S32500019F8083E100007FE803A6382100184E8000207FE802A697E1FFE89061001C4BFF6205BB +S32500019FA08141001C812100207C6B1B789009001080EA00007C0700004082005C912A000011 +S32500019FC0912A000480A9000480C900007CA6285080CA00107CA62A1490AA00107D635B78F4 +S32500019FE04BFF61DD8121001C80A900087C050000418200148069000C80E900087CE803A618 +S3250001A0004E80002183E100007FE803A6382100184E80002080AA0004912500104BFFFFA496 +S3250001A020806300104E8000207FE802A697E1FFE09061002438C0FFFF90C100144BFF616552 +S3250001A04081610014814100247C6C1B78916100147C0B000040800010812A00007C09000015 +S3250001A060408200207D8363784BFF61558061001483E100007FE803A6382100204E8000204C +S3250001A08080E9000080C900047C073040408000208169000038EB000190E90000896B0000B5 +S3250001A0A0808A00103884FFFF908A001080E9000080C900047C0730404180FF9480E9001025 +S3250001A0C090EA0000900900104BFFFF847FE802A697E1FFE89061001C386000014BFFFD45E9 +S3250001A0E07C681B788083000438C4000190C3000480C1002098C400008061001C9101000833 +S3250001A1004BFFFE9183E100007FE803A6382100184E800020812100089123000480C1000CDD +S3250001A12038A000087CC62BD654C618387CC64A1490C300084E8000207FE802A697E1FFD844 +S3250001A14081810034816100307C6E1B787C0C00004181001483E100007FE803A638210028E0 +S3250001A1604E8000208143000480AA00047C0558404181001080CA00007C0600004082011C5E +S3250001A18080AE00047C0A28404081001C38CAFFFC80C6000080EAFFF87CC63A147C065800AD +S3250001A1A0418200A47D0B6214812A00047C0848004082001080EA00007C07000040820060D7 +S3250001A1C0808E00087C0A20404180002C3862829880AE000090A100089161000C9181001054 +S3250001A1E04BFF978183E100007FE803A6382100284E80002081AA0004916A00047DAB6B78DA +S3250001A20081AA0000918A0000394A00087DAC6B787C0D00004182FFD04BFFFFA880AA000420 +S3250001A2207D0C2850910A000480EA00007CA7621490AA000083E100007FE803A63821002845 +S3250001A2404E80002080CAFFF87C866214908AFFF87C8B621480AA00047C0428004082FF88A3 +S3250001A26080AA0000808AFFF87CA42A1490AAFFF880EA00007C0700004182FF6C394A000877 +S3250001A280388AFFFC80CA000490C40000810A0000910AFFF84BFFFFDC394A00084BFFFECC77 +S3250001A2A07FE802A697E1FFD881E1003081C1003481A100387C701B7881630004810B0000E4 +S3250001A2C07C08000041820028818B00047C0F00004182005C7C0C784040810028396B000879 +S3250001A2E0810B00007C0800004082FFE07C03037883E100007FE803A6382100284E800020C9 +S3250001A3007D0F7214812B00007D2C4A147C084840408100187C03037883E100007FE803A61E +S3250001A320382100284E8000207DEC7B787C0D0000408100147C8D62143884FFFF7C846B96B3 +S3250001A3407D8469D680CB000080EB00047CC63A147CCC30507C067040408000084BFFFF80E1 +S3250001A36081AB00047CEC721490EB00047D0C72147D0D4050812B00007D084850910B0000AB +S3250001A38080CB00007C06000040820028396B000838CBFFFC810B00049106000080AB000003 +S3250001A3A090ABFFF87C050000418200084BFFFFE07C0D6000418200207E03837891A100086D +S3250001A3C0918100207CCD605090C1000C4BFFFD6D818100207D83637883E100007FE803A6C9 +S3250001A3E0382100284E8000207FE802A697E1FFB8388002809081003438A001E090A1003808 +S3250001A40038C0000390C1003C90010040386100344800042180E100407C07000040820014A8 +S3250001A42083E100007FE803A6382100484E800020388000039082825480A1004090A2824812 +S3250001A44038E000A090E28250900282589002825C3900028091028260388001E0908282645C +S3250001A46038A2824838C2824880E600108106001490E5002091050024810600188086001C4C +S3250001A480910500289085002C7C0303783880FFFF9081000838C0FFFF90C1000C3900FFFF63 +S3250001A4A09101001048000641386000FF900100089001000C900100104800062D3862824817 +S3250001A4C038A1000890A1002C80E1002C900700008081002C9004000438C2824890C1001029 +S3250001A4E0390100143882824880A4001080C4001490A8000090C8000480C4001880E4001C87 +S3250001A50090C8000890E8000C900100244BFFCAB538E0000890E280A8900280AC8102800C4B +S3250001A52089080105910280B083E100007FE803A6382100484E8000207FE802A697E1FFB879 +S3250001A5407C691B7880C282487C0600004082001483E100007FE803A6382100484E80002015 +S3250001A5609061004C2C030008418202302C030009418201D02C03000A4182010480A282609A +S3250001A580810280B07CA8285080C280A87C062800418000103860000A4BFFFFA18121004C06 +S3250001A5A07129007F408100C8A8E280087C093800408000BC5528183880C2800C7D28321421 +S3250001A5C03881003C38A280A880C5000080E5000490C4000090E400043862824838E100087E +S3250001A5E090E100348081003488C900047CC607748101003C7CC8321490C4000080C1003457 +S3250001A600810100409106000480A2801090A10010390100149101003080A10030A8E90000F1 +S3250001A62090E50000808100309004000480C1003091210044A90900089106000880A10030C4 +S3250001A64088E2800A7CE7077490E5000C38E0000C90E100244BFFC96D808100448884000511 +S3250001A66080C1003C7C843214908280A883E100007FE803A6382100484E8000203900000892 +S3250001A680910280A88882800A7C840774810280AC7C882214908280AC88C2800A7CC6077431 +S3250001A6A080E282647CC63850810280AC7C0830004081000C80A2825C90A280AC386282488F +S3250001A6C038E1000890E10034808100349004000080C10034810280AC9106000438A2824881 +S3250001A6E090A1001038E1001490E10030808100309004000080C10030810280AC91060004C4 +S3250001A70080A1003080E2826090E500088081003088C2800A7CC6077454C6083C80E280AC72 +S3250001A7207CC63A1490C4000C900100244BFFC89583E100007FE803A6382100484E800020C3 +S3250001A740808280A83884FFF880A280B07C842BD67084000738C000087C84305080E280B0B5 +S3250001A7607C8439D680A280A87C852214908280A880E280A8808282607C0720004180FEF048 +S3250001A7803860000A4BFFFDB583E100007FE803A6382100484E80002080C280B038C6000899 +S3250001A7A0810280A87C0830004180FEC480A280B080E280A87CA5385090A280A83860002019 +S3250001A7C04BFFFD7980A280B080E280A87CA5385090A280A883E100007FE803A638210048BE +S3250001A7E04E8000207FE802A697E1FFF07C691B788101001838C8FFFF90C100187C080000F1 +S3250001A8004081002038E9000190E10014886900007C6307744BFFFD25812100144BFFFFD41F +S3250001A82083E100007FE803A6382100104E8000207FE802A697E1FFD87C6A1B7880E2801479 +S3250001A84080E7002090E10024388001E09083000438E0028090E3000038A0000390A3000802 +S3250001A860806300009141002C80EA00047C6339D638A0001090A100084BFFE6A13DA0017D47 +S3250001A88061AD78408181002C81610024906C000C80AC000080CC00047CA531D690AC0010BF +S3250001A8A0808B00303FE0FFFF63FFFFBF7FE42039908B0030810C000C7508E0003D2020009F +S3250001A8C07C0848004182020C80EC000C90EB085080EC0000810C00047CE741D654E7183887 +S3250001A8E038E7007F390000807CE743D654E7881C60E70D6690EB084038A000037C050000C6 +S3250001A900418200142C050002418201A02C050003418201687C0A03782C0A00104080001C3F +S3250001A9205546083C7CC65A14B1460E00394A00012C0A00104180FFEC808C0004548458289E +S3250001A9403FE0100063FF00217FE42378908B084880CC000054C6502A3FE0010063FF00E48F +S3250001A9607FE6337890CB084480C28014818600087D4C6BD67CCC53D67C0668004081000806 +S3250001A980394A00019141001C2C0A00104180000C38E0001090E1001CB00B097638E01FFF06 +S3250001A9A0B0EB0972A0AB097270A5FDFFB0AB097238A01FFFB0AB0970810B0ABC61085001F7 +S3250001A9C0910B0ABC810B0AB861085001910B0AB8A10B0AC27108AFFEB10B0AC24BFF579D44 +S3250001A9E080C100243D0055CC6108AA33910603804BFF578981410024808A02803FE0FFFF74 +S3250001AA0063FFFFE07FE4203938A281108101001C7CA5421488A500007C842B78908A028046 +S3250001AA204BFF575980A100243CE0AA3360E755CC90E503804BFF57458102825091028250D7 +S3250001AA4080A1002438E0000798E508584BFF572D8101002480A8084060A5000190A8084044 +S3250001AA60386000014BFF5D3183E100007FE803A6382100284E8000207C0A03782C0A010043 +S3250001AA804080FEB85544402E554520367C842B787C8453785545083C7CA55A14B0850E0024 +S3250001AAA0394A00014BFFFFD87C0A03782C0A00104080FE885546402E554720367CC63B786D +S3250001AAC07CC65378B0CB0E00394A00014BFFFFE080EC000C3FE0FFFF63FFFFFF7FE7383960 +S3250001AAE04BFFFDEC80810008548B273E80E1000C54EA273E80A1001054A9273E3FE0FFFF0F +S3250001AB0063FFFFFF7FE81A78710800FF5508083C80C2801480C600207D0832145565402E8D +S3250001AB20554620367CA533787CA54B78B0A80E00386000014E8000203821FFE83D4055CCA2 +S3250001AB40614AAA333D20FA209149030038C000C3B0C902009149032038E000C1B0E902204B +S3250001AB603CA0AA3360A555CC90A903209149034038C00082B0C90240382100184E800020E2 +S3250001AB807FE802A697E1FFE081410028906100247145000341820010386287E44BFF8E4D93 +S3250001ABA081410028812100243CC07C1060C643A690C900003C807C08608402A69089000405 +S3250001ABC03CE07C1260E743A690E900087544E0003CC020007C043000418200887D485378D3 +S3250001ABE07D0A437855053E7F4182000C2C05007F408200303FE003FF63FFFFFC7FE5503919 +S3250001AC003FE0480063FF00037FE52B7890A9000C83E100007FE803A6382100204E8000203A +S3250001AC205544843E64843C009089000C7144FFFF64846000908900103C807C08608403A678 +S3250001AC40908900143CE04E8060E7002190E9001883E100007FE803A6382100204E80002002 +S3250001AC603FE0FFFF63FFFFFF7FE850394BFFFF747FE802A697E1FFE89061001C8082E53011 +S3250001AC802C0400304180000C386287EC4BFF8D5D80C1001C7D4602148082E53039040001B4 +S3250001ACA09102E5305484203638A2E03038A502007D642A145547103A38C2E0307CE7321436 +S3250001ACC080E7000090EB000881010020910B000080E1002490EB00045544103A38E2E03034 +S3250001ACE07C843A149164000080A28014816500202C0A00104180003038EAFFF070E7001F90 +S3250001AD0038C000017CC7383080CB09487CC73B7890EB094883E100007FE803A63821001845 +S3250001AD204E8000202C0A000841800038714800075508083C38E0001F7D08385039200001E8 +S3250001AD407D284030808B00147C884378910B001483E100007FE803A6382100184E80002076 +S3250001AD605544083C608400013900001F7C84405038A000017CA4203080AB00147CA42378DF +S3250001AD80908B001483E100007FE803A6382100184E8000207FE802A697E1FFE03D4055CCA6 +S3250001ADA0614AAA33810280148128002080A900043FE0FFFF63FFFFF37FE5283990A9000484 +S3250001ADC09009001438E0FFFF90E900189009094038E0FFFF90E90944900909483CE000E173 +S3250001ADE060E79F0090E9094080A9094060A5008090A909409149030039000001B109020058 +S3250001AE0080C9001464C6004090C900149149030C4BFF53693860FFFF4BFF53E17C090378F4 +S3250001AE202C0930004080002C7D234B789121001C3D00FFC2610803A8910100084BFFFD4551 +S3250001AE4080E1001C392701002C0930004180FFDC83E100007FE803A6382100204E80002031 +S3250001AE607FE802A697E1FFD87C6A1B787C0903782C09002840800064386288065526103A86 +S3250001AE8038A284307CC62A1480C6000090C10008810A00009101000C912100245528103A38 +S3250001AEA038E284307D083A1481080004910100109141002080AA000490A100144BFF8AA5DD +S3250001AEC0810100243928000280C10020394600082C0900284180FFA483E100007FE803A645 +S3250001AEE0382100284E8000207FE802A697E1FFE87C6A1B789061001C80C3000054C9C23E88 +S3250001AF002C090005418200802C0900094182005C38C0000190C280B47C0900004180003C4F +S3250001AF202C09001540800034386288345524103A390295A07C8442148084000090810008D0 +S3250001AF404BFF8A218061001C4BFFFF19386288424BFF8A11480000003862881B912100080E +S3250001AF604BFF8A014BFFFFE07D435378900100084BFF7B8983E100007FE803A63821001875 +S3250001AF804E8000204800001583E100007FE803A6382100184E8000207FE802A697E1FFD82E +S3250001AFA09061002C810280148168002091610018890B001C550CF0BE7D8A0E7091810024C9 +S3250001AFC071880001418200E02C0A00044082002438800001B08B09304BFF51A1818100241E +S3250001AFE081610018A0AB093054A5AAFE39450010914100205545103A3882E0307CA52214A6 +S3250001B000814500007C0A00004082000848000000808A000C7C0400004182002038A0001F5B +S3250001B0207CAC285038C000017CC5283080CB00107CC52B7890AB00108061002C80EA0004D2 +S3250001B04090E100089141001C80EA00007CE803A64E80002180C1001C814600087C0A00006A +S3250001B060418200084BFFFFD480C100202C060010418000248101001880A1002038A5FFF0B2 +S3250001B080392000017D2528308088094C7C852B7890A8094C83E100007FE803A638210028D2 +S3250001B0A04E800020394A00084BFFFF487C691B7888A3000054A5402E888300017CA52378AD +S3250001B0C054A5402E88C300027CA5337854A5402E88C300037CA533783CE0FEEF60E70F1EEB +S3250001B0E07C05380040820030886300205463402E88C900217C6333785463402E88E90022BA +S3250001B1007C633B785463402E890900237C6343784E8000207C0303784E8000207FE802A63D +S3250001B12097E1FFE8386001F43CA0FFC260A5B21C90A100089001000C4BFF65959062822CF2 +S3250001B14038628BE04BFF881D83E100007FE803A6382100184E8000207FE802A697E1FFB8E3 +S3250001B160818100507C6B1B788083000480A300007C8520502C040040408000183860FFFF83 +S3250001B18083E100007FE803A6382100484E80002081430000890A00005508402E88EA000110 +S3250001B1A07D083B785508402E892A00027D084B785508402E888A00037D0823783CA0FEEFBF +S3250001B1C060A50F1E7C082800418200183860FFFF83E100007FE803A6382100484E80002016 +S3250001B1E0900282EC88CA001054C6402E88AA00117CC62B7854C6402E88EA00127CC63B7835 +S3250001B20054C6402E88EA00137CCE3B78888A00145484402E890A00157C8443785484402E08 +S3250001B22088AA00167C842B785484402E88AA00177C842B789081003888EA001854E7402E6E +S3250001B24088CA00197CE7337854E7402E890A001A7CE7437854E7402E890A001B7CE7437885 +S3250001B26090E1003488AA000C54A5402E888A000D7CA5237854A5402E88CA000E7CA533780F +S3250001B28054A5402E88CA000F7CA5337890A10030890A00045508402E88EA00057D083B78A1 +S3250001B2A05508402E892A00067D084B785508402E888A00077D0D237888CA000854C6402ED0 +S3250001B2C088AA00097CC62B7854C6402E88EA000A7CC63B7854C6402E88EA000B7CC63B7854 +S3250001B2E090C1002880C3000038C6002090C3000081430000888A00005484402E890A00016A +S3250001B3007C8443785484402E88AA00027C842B785484402E88AA00037C842B782C0406EB0F +S3250001B3204182002038628BE24BFF86393860FFFF83E100007FE803A6382100484E8000207A +S3250001B34088CA001454C6402E88AA00157CC62B7854C6402E88EA00167CC63B7854C6402E3F +S3250001B36088EA00177CC63B7890CC000081030000390800209103000080EC000074E7E000CC +S3250001B3803D0020007C0740004182015480CC00007CC3337890C100449161004C916100086B +S3250001B3A091A1000C91C1001038A28BFF90A1001448000141816100287C6A1B787C030000B1 +S3250001B3C04082002038628C044BFF85993860FFFF83E100007FE803A6382100484E80002059 +S3250001B3E07C0B00004182005C38EA0FFF3FE0FFFF63FFF0007FE3383980E1004C90E1000808 +S3250001B4009161000C810100389101001038C28C1790C10014480000DD7C6A1B787C030000AC +S3250001B4204082002038628C1C4BFF85393860FFFF83E100007FE803A6382100484E80002040 +S3250001B44080C100307C060000418200407D435378914100408081004C8084000090810008E8 +S3250001B460808100309081000C48001AF981610030808100407D445A1480E1004C80C70000A6 +S3250001B4807C865A1490870000808282EC80C100347C0430004182003038628C2F810282EC50 +S3250001B4A09101000880C1003490C1000C4BFF84B53860FFFF83E100007FE803A638210048EB +S3250001B4C04E80002080C100447C66505083E100007FE803A6382100484E80002080CC000021 +S3250001B4E03FE0FFFF63FFFFFF7FE630394BFFFEA47FE802A697E1FFE07C6A1B7838628C67A2 +S3250001B5008081003490810008914100249141000C80A1002C90A100104BFF84498101002CAF +S3250001B5207C080000408200188061002483E100007FE803A6382100204E80002080610028BD +S3250001B5403902EE00910100089001000C480003257C030000408000187C03037883E100005F +S3250001B5607FE803A6382100204E8000208061002838E20A0890E10008388000089081000CC2 +S3250001B580480002F1814100287C030000408000187C03037883E100007FE803A63821002041 +S3250001B5A04E80002080CA000480EA00007CC7305080A1002C7C0628004080002038628C7F9F +S3250001B5C04BFF83A17C03037883E100007FE803A6382100204E800020386001F43D00FFC296 +S3250001B5E06108B21C910100089001000C4BFF60E1814100289062822C80610024810A000031 +S3250001B60091010008810A00008121002C7D084A149101000C38E2EE0090E1001039020A08D9 +S3250001B6209101001480A1003090A100184800006D906100248062822C4BFF61759002822C09 +S3250001B64038628C8E4BFF831D814100247C0A00004082002038628C904BFF83097C03037871 +S3250001B66083E100007FE803A6382100204E80002080E100288081002C80C700007C862214B3 +S3250001B680908700007D43537883E100007FE803A6382100204E8000203821FFE8820100243F +S3250001B6A081610030812100207C6C1B78556536BE2C050013418201942C05001F4182018C4A +S3250001B6C02C05003B418201842C05003F4182017C81A282EC7C0980404080016088890000F7 +S3250001B6E07C8F2378392900017C0E03787C8A26707C0A00004082002C7D6A5B78914C00008E +S3250001B700398C00047DAD521471EA000F39CE00012C0E00014082FFC07C0A00004182FFDC77 +S3250001B7202C0A00014082009488E9000354E7402E88C900027CE7337854E7402E89090001BB +S3250001B7407CE7437854E7402E890900007CEA4378392900047C098040408100107C030378F2 +S3250001B760382100184E800020554736BE2C070013418200202C07001F418200182C07003B0F +S3250001B780418200102C07003F418200084BFFFF703FE0FC0063FFF8017FE8503955478BFE4E +S3250001B7A070E707FE7D083B78714407FE548478207D0A23784BFFFF48280A000841810044D1 +S3250001B7C038AAFFFE54A5402E890900007CA5437854A5103A80C1002C7CA5321480A500046E +S3250001B7E0890900017CAA4378392900027C0980404081FF787C030378382100184E80002094 +S3250001B800390AFFF75508402E88C900007D0833785508103A80E100287D083A1481480004CC +S3250001B820392900017C0980404081FF407C030378382100184E80002091A282EC7D83637884 +S3250001B840382100184E8000203FE0FC0063FFF8017FE6583955658BFE70A507FE7CC62B78D4 +S3250001B860716707FE54E778207CCB3B784BFFFE647FE802A697E1FFD08083000480A30000EB +S3250001B8807C8520502C040002408000183860FFFF83E100007FE803A6382100304E800020A5 +S3250001B8A081030000890800005508402E9061003480E3000088E700017D083B7838628CB398 +S3250001B8C09101001C910100084BFF809981C100388161003480CB000038C6000290CB000080 +S3250001B8E08081001C39A4FFFE7C0D00004081002C810B0004812B00007D0940507C08680096 +S3250001B900408000183860FFFF83E100007FE803A6382100304E800020900E0000814B00005D +S3250001B92080CB00007D866A14810B00007CC86A1490CB00007C0D03787C0A60404080009011 +S3250001B9407C0B03787C0A6040418000183860FFFF83E100007FE803A6382100304E8000205E +S3250001B9605568383088CA000070C6007F7D0B33787D455378394A000188A5000070A500808E +S3250001B980418200207C0A60404180FFD83860FFFF83E100007FE803A6382100304E8000207E +S3250001B9A07DAD5A14808E000038A4000190AE00005484103A7C84721480E1003C7DA53830F0 +S3250001B9C090A400047C0A60404180FF787C03037883E100007FE803A6382100304E800020E5 +S3250001B9E03821FFF07C6B1B7880A1001C810100247D45421480C10018808100207D26221430 +S3250001BA008081001C7C0A20404080000839290001914B0004912B0000382100104E800020FE +S3250001BA203821FFF07C6B1B788101001C80C100247D4640508081001880E100207D27205039 +S3250001BA4080E1001C7C0A3840408100083929FFFF914B0004912B0000382100104E80002048 +S3250001BA603821FFD8CA2100307C6E1B78DA210020810100203FE0000F63FFFFFF7FE84039CC +S3250001BA80650C001081A10024810100205508653E710807FF38C004337D2830507C0B037861 +S3250001BAA07C0A03787C090000418000B02C090020408000847C090000408200607DAB6B783D +S3250001BAC07D8A637880A1002074A580007C050000418200207C0B0000418200287C040378D2 +S3250001BAE07D6B20503FE0FFFF63FFFFFF7FEA5278914E0000916E0004382100284E800020E6 +S3250001BB007C0703787D4A3850914E0000916E0004382100284E8000207DA54C3038C00020CA +S3250001BB207CC930507D8630307CAB33787D8A4C304BFFFF942C0900204082000C7D8B63789E +S3250001BB404BFFFF842C0900404080FF7C38C9FFE07D8B34304BFFFF707C0703787D29385030 +S3250001BB602C09000A418100207DAB48307D85483038C000207CC930507DA634307CAA33784E +S3250001BB804BFFFF44FC80881ED8828020814280244BFFFF347FE802A697E1FFE8C061002062 +S3250001BBA0D86100084BFFFEBD83E100007FE803A6382100184E8000203D20433080E1000430 +S3250001BBC074E780007C0700004182009C808100087C0400004182007C7C0603788101000852 +S3250001BBE07CC8305090C1000880C100043FE0FFFF63FFFFFF7FE6327890C1000480E1000496 +S3250001BC00912280206CE6800090C28024C8228020FC21D828C8828428FC01013280A100080C +S3250001BC20912280206CA4800090828024C8628020FC63D828FC03E0004080000CC8428428DA +S3250001BC40FC63102AFC00182AFC1C00284E8000207C04037880C100047C8620509081000411 +S3250001BC604BFFFF9C80A10004912280206CA4800090828024C8628020FC63D828C84284283B +S3250001BC80FC0300B281010008912280206D07800090E28024C8228020FC21D828FC01E00081 +S3250001BCA04080000CC8428428FC21102AFC00082A4E8000207FE802A697E1FFF038C1000415 +S3250001BCC038E10014810700008087000491060000908600044BFFFEE5FC00001883E1000047 +S3250001BCE07FE803A6382100104E8000203821FFD83DA080008241003C822100408161002C59 +S3250001BD008181003081210034814100387C0A00004082000C7C090000418200F47C0B68405B +S3250001BD20418000E07C0F03787C0E03787C096840418000147C096800408200307C0A784031 +S3250001BD40408000285525083C55480FFE7CA94378554A083C39CE00017C0968404180FFE8EC +S3250001BD607C0968004182FFD87C0F03787C0D03787C0E00004180006455E4083C55A70FFEF6 +S3250001BD807C8F3B7855AD083C7C0B4840418100147C0B4800408200287C0C50404180002001 +S3250001BDA07D9063787D8A60507C0C804040810008396BFFFF7D69585061AD00015547F87E7B +S3250001BDC05525F8007CEA2B785529F87E39CEFFFF7C0E00004080FFA47C1200004182000C9E +S3250001BDE091B2000491F200007C1100004182000C9191000491710000382100284E8000207F +S3250001BE007D6D5B787D8F63784BFFFF207D8C53964BFFFF0C7FE802A697E1FFE07C691B78E9 +S3250001BE2080E100287C07000040820010808100307C0400004182005438E1000439010028D6 +S3250001BE408088000080A800049087000090A7000438A1000C38C1003080E600008106000456 +S3250001BE6090E5000091050004912100147C06037890C100184BFFFE7983E100007FE803A64B +S3250001BE80382100204E8000207C0803789109000080C1002C80A100347CC62B9690C9000479 +S3250001BEA083E100007FE803A6382100204E8000207FE802A697E1FFE07C691B788101002818 +S3250001BEC07C0800004082001080A100307C05000041820054390100043881002880A40000D9 +S3250001BEE080C4000490A8000090C8000438C1000C38E10030810700008087000491060000E7 +S3250001BF00908600047C04037890810014912100184BFFFDDD83E100007FE803A63821002005 +S3250001BF204E8000207C0403789089000080E1002C80C100347FE733967FFF31D67CFF38503F +S3250001BF4090E9000483E100007FE803A6382100204E800020808300047C0400004082001821 +S3250001BF6080A300007C0603787CA5305090A300004E800020808300047C0503787C8428505D +S3250001BF8090830004810300003FE0FFFF63FFFFFF7FE84278910300004E8000207FE802A6D0 +S3250001BFA097E1FFD07C691B78906100348081003C7C84FE7080C100387C06200040820018F6 +S3250001BFC0810100447D08FE7080A100407C054000418200AC80E1003854E70FFE90E1002C92 +S3250001BFE07C07000041820010386100384BFFFF698121003480E1004054E70FFE90E1002809 +S3250001C0007C07000041820010386100404BFFFF498121003438E100043901003880880000EB +S3250001C02080A800049087000090A7000438A1000C38C1004080E600008106000490E50000F7 +S3250001C04091050004912100147C06037890C100184BFFFC9D80E1002C808100287C072000D7 +S3250001C0604182000C806100344BFFFEED83E100007FE803A6382100304E8000208081003C78 +S3250001C080810100447C8443D69089000480E900047CE7FE7090E9000083E100007FE803A672 +S3250001C0A0382100304E8000207FE802A697E1FFD07C6A1B78906100348101003C7D08FE705D +S3250001C0C080A100387C0540004082001880E100447CE7FE70808100407C043800418200A48F +S3250001C0E080C1003854C60FFE90C1002C7C06000041820010386100384BFFFE5D814100345B +S3250001C10080C1004054C60FFE7C06000041820010386100404BFFFE418141003438C10004C6 +S3250001C12038E10038810700008087000491060000908600043881000C38A1004080C5000040 +S3250001C14080E5000490C4000090E400047C07037890E10014914100184BFFFB9580C1002CEF +S3250001C1607C0600004182000C806100344BFFFDE983E100007FE803A6382100304E80002037 +S3250001C1808101003C80E100447FE83BD67FFF39D67D1F4050910A000480CA00047CC6FE7067 +S3250001C1A090CA000083E100007FE803A6382100304E8000203821FFF081610020814100180F +S3250001C1C02C0B0020418000387D46FE7090C300002C0B0040418000147D48FE70910300046D +S3250001C1E0382100104E800020390BFFE07D48463091030004382100104E8000207C0B00000D +S3250001C200418100189143000080E1001C90E30004382100104E8000207D465E3090C300007A +S3250001C22038E000207CEB38507D47383080A1001C7CA55C307CE72B7890E3000438210010D4 +S3250001C2404E8000203821FFF081410020816100182C0A0020418000387C05037890A3000047 +S3250001C2602C0A0040418000147C05037890A30004382100104E800020390AFFE07D68443067 +S3250001C28091030004382100104E8000207C0A0000418100189163000080E1001C90E3000460 +S3250001C2A0382100104E8000207D66543090C3000038E000207CEA38507D67383080A1001CB7 +S3250001C2C07CA554307CE72B7890E30004382100104E8000203821FFF0814100208161001CB6 +S3250001C2E02C0A0020418000387C05037890A300042C0A0040418000147C05037890A300003B +S3250001C300382100104E800020390AFFE07D68403091030000382100104E8000207C0A0000D7 +S3250001C320418100189163000480E1001890E30000382100104E8000207D66503090C3000427 +S3250001C34038E000207CEA38507D673C3080A100187CA550307CE72B7890E3000038210010A4 +S3250001C3604E80002080C1000880A100107CC6283890C300008081000C810100147C8440383E +S3250001C380908300044E8000208101000880E100107D083B789103000080C1000C80A1001448 +S3250001C3A07CC62B7890C300044E80002080A10008812100107CA54A7890A300008101000CCD +S3250001C3C080E100147D083A78910300044E8000208121000880E9000090E300008089000491 +S3250001C3E09083000480C9000438C6000190C90004808900047C0400004082001080A90000EE +S3250001C40038A5000190A900004E8000208121000880C9000090C300008109000491030004A4 +S3250001C420810900047C08000040820010808900003884FFFF90890000808900043884FFFF6E +S3250001C440908900044E800020812100087C6A1B7880A9000438A5000190A9000481090004D1 +S3250001C4607C0800004082001080890000388400019089000080890000908A000080C9000410 +S3250001C48090CA00044E800020812100087C6A1B7880E900047C0700004082001081090000DA +S3250001C4A03908FFFF91090000810900043908FFFF9109000481090000910A000080A90004DF +S3250001C4C090AA00044E8000207FE802A697E1FFD0814100388121003C90610034390100207C +S3250001C4E08083000080A300049088000090A8000480A100402C0500064181029C4182023CBE +S3250001C5002C05000341810164418201002C050001418200942C05000241820030480010D915 +S3250001C5208101003438A1002080C5000080E5000490C8000090E8000483E100007FE803A64F +S3250001C540382100304E80002088AA000090A1002C7C07037890E1002838610020390100083C +S3250001C5603881002880A4000080C4000490A8000090C8000438C1001038E1004481070000E5 +S3250001C5808087000491060000908600047D2803A64E80002180C100388101002499060000DD +S3250001C5A04BFFFF8088AA00007CA5077490A1002C80E1002C54E70FFE90E100283861002059 +S3250001C5C038A1000838C1002880E600008106000490E500009105000439010010388100440B +S3250001C5E080A4000080C4000490A8000090C800047D2803A64E8000218101003880A10024F8 +S3250001C60098A800004BFFFF1CA90A00009101002C80A1002C54A50FFE90A100283861002098 +S3250001C620390100083881002880A4000080C4000490A8000090C8000438C1001038E100446A +S3250001C640810700008087000491060000908600047D2803A64E80002180C100388101002433 +S3250001C660B10600004BFFFEBC2C050004418200702C050005418200084BFFFEA4808A000099 +S3250001C6809081002C8081002C54840FFE908100283861002038E100083901002880880000C7 +S3250001C6A080A800049087000090A7000438A1001038C1004480E600008106000490E5000069 +S3250001C6C0910500047D2803A64E80002180A1003880E1002490E500004BFFFE48A10A0000EE +S3250001C6E09101002C7C05037890A100283861002038C1000838E10028810700008087000492 +S3250001C70091060000908600043881001038A1004480C5000080E5000490C4000090E4000401 +S3250001C7207D2803A64E8000218081003880C10024B0C400004BFFFDEC808A00009081002C29 +S3250001C7407C040378908100283861002038A1000838C1002880E600008106000490E500007D +S3250001C76091050004390100103881004480A4000080C4000490A8000090C800047D2803A683 +S3250001C7804E8000218101003880A1002490A800004BFFFD902C050007418200DC2C05000885 +S3250001C7A0418200D42C0500094182006C2C05000A418200084BFFFD6880CA000090C1002CF6 +S3250001C7C07C06037890C100283861002038E10008390100288088000080A800049087000055 +S3250001C7E090A7000438A1001038C1004480E600008106000490E50000910500047D2803A683 +S3250001C8004E80002180A1003880E1002490E500004BFFFD1080CA000090C1002C80C1002C44 +S3250001C82054C60FFE90C10028386100203881000838A1002880C5000080E5000490C40000D4 +S3250001C84090E4000438E10010390100448088000080A800049087000090A700047D2803A6DE +S3250001C8604E80002180E1003880810024908700004BFFFCB0386100203881000880AA000053 +S3250001C88080CA000490A4000090C4000438C1001038E1004481070000808700049106000027 +S3250001C8A0908600047D2803A64E80002180C10038390100208088000080A8000490860000FD +S3250001C8C090A600044BFFFC5C3821FFF081010018910300047C06037890C300003821001042 +S3250001C8E04E8000203821FFF081010018910300047D06FE7090C30000382100104E8000202E +S3250001C9003821FFF080A1001890A300047C08037891030000382100104E8000203821FFF026 +S3250001C92080A1001890A300047CA8FE7091030000382100104E8000203821FFF080E1001842 +S3250001C94090E300047C05037890A30000382100104E8000203821FFF080E1001854E7801E39 +S3250001C9607CE88670910300047D06FE7090C30000382100104E8000203821FFF080A10018A2 +S3250001C98070A5FFFF90A300047C04037890830000382100104E8000203821FFF080C1001840 +S3250001C9A054C6C00E7CC7C67090E300047CE5FE7090A30000382100104E8000203821FFF0F7 +S3250001C9C080810018708400FF908300047C08037891030000382100104E8000203821FFF0FB +S3250001C9E080810018708400FF5483C00E7C63C670382100104E80002080610008706300FF58 +S3250001CA004E8000203821FFF0808100187084FFFF5483801E7C638670382100104E8000202D +S3250001CA20806100087063FFFF4E800020806100084E800020806100084E80002080610008B0 +S3250001CA404E800020806100084E800020810100087C0800004082001880A100047C0500007C +S3250001CA604082000C7C0303784E800020386000014E80002080E10008808100107C07200055 +S3250001CA804082001480C100048101000C7C0640004182000C7C0303784E80002038600001D4 +S3250001CAA04E80002080A1000880E100107C0538004082001C8081000480C1000C7C0430004E +S3250001CAC04082000C7C0303784E800020386000014E8000208101000480A1000C7C082800B3 +S3250001CAE04180002480E100048081000C7C0720004082001C80C10008810100107C0640407A +S3250001CB004080000C386000014E8000207C0303784E80002080A1000480E1000C7C05380088 +S3250001CB20418000248081000480C1000C7C0430004082001C8101000880A100107C08284082 +S3250001CB404181000C386000014E8000207C0303784E80002080E100048081000C7C0720007C +S3250001CB604181002480C100048101000C7C0640004082001C80A1000880E100107C053840C2 +S3250001CB804081000C386000014E8000207C0303784E8000208081000480C1000C7C04300050 +S3250001CBA0418100248101000480A1000C7C0828004082001C80E10008808100107C072040EE +S3250001CBC04180000C386000014E8000207C0303784E80002080C100048101000C7C0640403D +S3250001CBE04180002480A1000480E1000C7C0538004082001C8081000880C100107C043040D6 +S3250001CC004080000C386000014E8000207C0303784E8000208101000480A1000C7C08284033 +S3250001CC204180002480E100048081000C7C0720004082001C80C10008810100107C06404038 +S3250001CC404181000C386000014E8000207C0303784E80002080A1000480E1000C7C05384005 +S3250001CC60418100248081000480C1000C7C0430004082001C8101000880A100107C08284040 +S3250001CC804081000C386000014E8000207C0303784E80002080E100048081000C7C072040FC +S3250001CCA04181002480C100048101000C7C0640004082001C80A1000880E100107C05384081 +S3250001CCC04180000C386000014E8000207C0303784E8000208121000C814100088081001484 +S3250001CCE080A100107CC921D67CE920167D0451D67CE742147D0549D67CE7421490C3000413 +S3250001CD0090E300004E8000208881000B3863FFFF8CC300017C062000418200107C060000B7 +S3250001CD204082FFF07C0303784E800020906100048081000C7C0400004081007C80A100086B +S3250001CD4054A5063E50A5442E50A5801E7CA62B787CA72B787CA82B782C04001040810050F2 +S3250001CD607069000741820018212900087D2103A67CA01D2A7C634A147C8920507C892671A7 +S3250001CD804081002C7D2903A690A300003943000890C3000490EA0000386A0008910A00047F +S3250001CDA04200FFE85484073F4182000C7C8103A67CA01D2A806100044E8000209061000485 +S3250001CDC08121000C7C6A1B787C090000418200A841800184816100082C0900104081008C73 +S3250001CDE07DAB4A147D8A4A147C0A5840418100CC7D67527870E7000340820084714700038C +S3250001CE004182002020E700047D2748507CE103A67E005C2A7D6B3A147E00552A7D4A3A148F +S3250001CE207D2E2671408100447DC903A6396BFFFC394AFFFC860B0004960A0004862B0004AA +S3250001CE40962A0004860B0004960A0004862B0004962A00044200FFE05529073F4182001895 +S3250001CE60396B0004394A00047D2103A67E005C2A7E00552A806100044E8000207D2E26711F +S3250001CE80408100247DC903A67E0B84AA396B00107E0A85AA394A00104200FFF05529073F0D +S3250001CEA04182FFD47D2103A67E005C2A7E00552A806100044E8000202C090004418000843C +S3250001CEC07DA7627870E700034082007871A70003418200188E0DFFFF9E0CFFFF3929FFFF22 +S3250001CEE071A700034082FFF07D2E2671408100347DC903A6860DFFFC960CFFFC862DFFFC60 +S3250001CF00962CFFFC860DFFFC960CFFFC862DFFFC962CFFFC4200FFE05529073F4182FF58B8 +S3250001CF207D2E16714081001C7DC903A6860DFFFC960CFFFC4200FFF8552907BF4182FF384A +S3250001CF407C0D58404081FF308E0DFFFF9E0CFFFF4BFFFFF090000000806100044E800020DC +S3250001CF604BFFFE5C3821FFD08281003881C1003C7C731B787C6B1B787C1203787C0D03781C +S3250001CF807C1003787C0F0378888B00007C8407742C04000C41810268418202502C04000939 +S3250001CFA0418202482C04000A418202402C04000B4182023888CB00007CC607742C06002D77 +S3250001CFC04182020888EB00007CE707742C07002B418201F87C0E00004082001888AB00007B +S3250001CFE07CA507742C050030418201B039C0000A2C0E0002418000782C0E002441810070B1 +S3250001D0002C0E00104082001488EB00007CE707742C070030418200F07C0D037838A0FFFFA8 +S3250001D0207E25739688CB00007CC607747CCA33787DCC73782C0600304180000C2C0A00396A +S3250001D040408100BC2C0A00614180000C2C0A007A408100A42C0A00414180000C2C0A005AFF +S3250001D0604081008C7C0C7000418000547C100000408200087E6B9B787C14000041820008A2 +S3250001D080917400007C0F0000418200103860FFFF382100304E8000207C12000041820014B4 +S3250001D0A07C0303787C6D1850382100304E8000207DA36B78382100304E8000207C0D8840DC +S3250001D0C04081000839E000017CAD71D67D4562147C0A68404080000839E000017D4D537819 +S3250001D0E0396B00013A1000014BFFFF3C398AFFC94BFFFF74398AFFA94BFFFF6C398AFFD0BA +S3250001D1004BFFFF64890B00017D0807742C08007841820018888B00017C8407742C04005828 +S3250001D120418200084BFFFEF488AB00027CA507742C0500304180001C88CB00027CC60774C0 +S3250001D1402C0600394181000C396B00024BFFFECC88EB00027CE707742C0700614180001419 +S3250001D160890B00027D0807742C0800664081FFDC888B00027C8407742C0400414180FE9C80 +S3250001D18088AB00027CA507742C0500464181FE8C396B00024BFFFE8439C00008890B0001EC +S3250001D1A07D0807742C08007841820018888B00017C8407742C040058418200084BFFFE3483 +S3250001D1C039C000104BFFFE2C7D685B78396B0001890800007D0807742C08002D4082FDF8C5 +S3250001D1E03A4000014BFFFDF0396B0001888B00007C8407742C04000C4081FDA02C04000D6C +S3250001D2004182FFE82C0400204182FFE04BFFFDA87FE802A697E1FFD8814100309061002C0F +S3250001D22088AA00007CA5077490A100207C0500004082001483E100007FE803A6382100287C +S3250001D2404E8000207D435378480001819061001C8061002C80A1002090A100084BFFFAADFF +S3250001D2607C691B787C0900004182005C7D234B789121002480810030908100088101001C6A +S3250001D2809101000C480000CD812100247C030000408200187D234B7883E100007FE803A6DE +S3250001D2A0382100284E8000203869000180C1002090C100084BFFFA557C691B787C09000006 +S3250001D2C04082FFAC7C03037883E100007FE803A6382100284E8000207FE802A697E1FFE88F +S3250001D2E07C691B7880A100207C050000408200247D234B787C080378910100084BFFFA0DBA +S3250001D30083E100007FE803A6382100184E8000207C040378908100147D234B78810100200E +S3250001D320910100084BFFF9E57C0300004182001039230001906100144BFFFFE08061001452 +S3250001D34083E100007FE803A6382100184E8000203821FFF081A100188141001C7C6C1B7818 +S3250001D3607C0A0000408100587D896378398C0001892900007D2907747DAB6B7839AD00019B +S3250001D380896B00007D6B0774394AFFFF7C095800418200247C095840408100103860000163 +S3250001D3A0382100104E8000203860FFFF382100104E8000207C0900004082FFA87C0303783A +S3250001D3C0382100104E8000207FE802A697E1FFF0906100147C07037890E100084BFFF92D8D +S3250001D3E0810100147C68185083E100007FE803A6382100104E8000207FE802A697E1FFE013 +S3250001D400814100287C691B789061001C7D234B789121002491410028914100087C0803788A +S3250001D4209101000C3900271091010010480001617C0300004082001880A100243925271058 +S3250001D44081010028394827104BFFFFC48061001C83E100007FE803A6382100204E8000207E +S3250001D4603821FFF0818100187C6B1B787D695B78396B0001892900007D2907747D8A6378B6 +S3250001D480398C0001894A00007D4A07747C095000418200247C09504040810010386000016F +S3250001D4A0382100104E8000203860FFFF382100104E8000207C0900004082FFB47C0303782D +S3250001D4C0382100104E8000203821FFE8812100247C6D1B78818100207C0900404081005074 +S3250001D4E07DAB6B7839AD0001896B00007D8A6378398C0001894A00007C0B50004182002406 +S3250001D5007C0B50404081001038600001382100184E8000203860FFFF382100184E8000202F +S3250001D5203929FFFF7C0900404181FFB87C030378382100184E8000203821FFF08121001CE7 +S3250001D5407C6A1B7880E1001870EB00FF7C090040408100307D475378394A000188E7000040 +S3250001D5607C07580040820010386AFFFF382100104E8000203929FFFF7C0900404181FFD842 +S3250001D5807C030378382100104E8000203821FFF0812100207C6A1B78816100188081001C99 +S3250001D5A0708C00FF7C090040408100407D465378394A00017D645B78396B0001888400002C +S3250001D5C0988600005484063E7C046000408200107D435378382100104E8000203929FFFF16 +S3250001D5E07C0900404181FFC87C030378382100104E8000207C040378808400007C04000006 +S3150001D600418200084BFFFFF04E8000200000000021 +S3250001D61000810E02001415F0001403E80000000000146530000000010000000000000000A0 +S3250001D6300000000000000000FFFFFFFF0000001E0000001D0000001C0000001B0000000065 +S3250001D6500000000000000000000000000000000000000000000000000000000000000000B3 +S3250001D670000000000000000000000000000000000000000000000000000000000000000093 +S3250001D690FFFFFFFF00000A0000000A2000000A4000000A6000140104000000000000000076 +S3250001D6B0000000000000000000000000000000012A2A2A000000000023706C616E392E6936 +S3250001D6D06E690A00000000005250587369676E61747572653D312E300A4E414D453D71627F +S3250001D6F0727063670A53544152543D46464332303130300A56455253494F4E3D312E310AC9 +S3250001D710000000000001000000000401080205030C06060909070710100000000000000082 +S3250001D7306672656562007167657400000000000000141BAF0000000000000000000000003F +S3250001D7500000000000000000000000000000000000000000000000000000000000000000B2 +S3250001D770000000000000000000000000000000000000000000000000000000000000000092 +S3250001D79000000000000000000000000000000000626F6F74006469736B00626F6F740075EA +S3250001D7B06172743A207374617274207472616E736D697373696F6E0A00756172743A2074A5 +S3250001D7D0696D656F75740A006E007900000000000000000000000000001403200000000077 +S3250001D7F0000000000000000000000000000000000000000000000000000000000000000012 +S3250001D8100000000000000000000000000000000000000000000000000000000000000000F1 +S3250001D8300000000000000000FFC206F000000000000000000000000000000000000000001A +S3250001D8500000000000000000000000000000000000000000000000000000000000000000B1 +S3250001D87000000000000000000000000000000000000000000000000000141A00FFC26E38FC +S3250001D89000141A04FFC26E3800000000000000006D6170667265653A2025733A206C6F735E +S3250001D8B0696E672030782575582C2025640A000000141A9300141AA700141AB300141AC312 +S3250001D8D0000000000014054000000000000000006E6577616C61726D000000000000000081 +S3250001D8F00000000000000000F1A55A1FFFC2363000000000000000000000000000000000DB +S3250001D9100000000000000000FFFFFFFF0000000000000004000000080000000C00000000DC +S3250001D9306275666665722064657363726970746F7273006264616C6C6F63000000000000B3 +S3250001D95000141A810000000000141A860000000100141A8C00000002000000000000000090 +S3250001D970FFFFFFFFFFFF000000000000000000000000000000000000000000000000000096 +S3250001D9900000000000000000000000000000000000000000000000000000000013880000D5 +S3250001D9B0FFFFFFFFFA203C00FA203D00FA203E00FA203F000000000000141FD70014203B7D +S3250001D9D06932632073657475702E2E2E0A004932432325780A0000000000000B00000000BA +S3250001D9F0000000000000000000140E4000000000000000200000000000000000000000008E +S3250001DA10000004000000000E0000000000000000000004000000000E0000000000000000CB +S3250001DA3041F0000000000000001407460014074C0014075100140754001407580014075B12 +S3250001DA500014075E0014076200140766001407690014076C0014076F001407720014077586 +S3250001DA70001407780014077B0014077E0014078100140784001407880014078C001407909D +S3250001DA9000140794001407980014079C001407A0001407A4001407A8001407AC001407B087 +S3250001DAB0001407B4001407B8001407BC001407C0001407C4001407C8001407CC001407D067 +S3250001DAD0001407D4001407D8FFC24714FFC2474CFFC24798FFC247BCFFC247C4FFC247CCD9 +S3250001DAF0FFC247F0FFC24830FFC24838FFC2485CFFC2488C000000000000000000000000A3 +S3250001DB100000000000000000000000000000000000000000000000000000000000000000EE +S3250001DB300000000000000000000000000000000000000000000000000000000000000000CE +S3250001DB507072656D617475726520454F460A002E00626164206D61676963203078256C7591 +S3250001DB7078206E6F74206120706C616E20392065786563757461626C65210A002564002BDF +S3250001DB9025644025382E386C7578002B25640A7374617274206174203078256C75780A0058 +S3250001DBB000000000000000000000000000000000000000000000000000000000000000004E +S3250001DBD000000000000A000000000000000000000000000000000000000000000000000024 +S3250001DBF0000000000000000000000000000000000000000000000000090000000000000005 +S3250001DC100000000102000000030000000400000500000006000700000800000000000000C9 +S3250001DC30726573657276656420300073797374656D207265736574006D616368696E652040 +S3250001DC50636865636B00646174612061636365737300696E737472756374696F6E206163DD +S3250001DC70636573730065787465726E616C20696E7465727275707400616C69676E6D656E24 +S3250001DC90740070726F6772616D20657863657074696F6E00666C6F6174696E672D706F6949 +S3250001DCB06E7420756E617661696C61626C650064656372656D656E74657200726573657218 +S3250001DCD0766564204100726573657276656420420073797374656D2063616C6C0074726123 +S3250001DCF06365207472617000666C6F6174696E6720706F696E742061737369737400726542 +S3250001DD10736572766564204600736F66747761726520656D756C6174696F6E0049544C4279 +S3250001DD30206D6973730044544C42206D6973730049544C42206572726F720044544C422033 +S3250001DD506572726F72004341555345005352523100504300474F4B004C52004352005845A5 +S3250001DD7052004354520052300052310052320052330052340052350052360052370052389B +S3250001DD900052390052313000523131005231320052313300523134005231350052313600E7 +S3250001DDB052313700523138005231390052323000523231005232320052323300523234008D +S3250001DDD0523235005232360052323700523238005232390052333000523331007365746866 +S3250001DDF0766563006F7574206F6620696E746572727570742068616E646C6572730025736B +S3250001DE1009252E386C757809257309252E386C75780A00657863657074696F6E2F696E741D +S3250001DE30657272757074202325780A00657863657074696F6E2025730A005E5020746F20DD +S3250001DE5072657365740A00005573696E6720666C61736820636F6E66696775726174696F20 +S3250001DE706E0A000A002573256400747970653D00706F72743D006972713D006D656D3D00E2 +S3250001DE9073697A653D0065613D00000000000000676574636C75737420402025640A00678B +S3250001DEB06574636C75737420256420696E2063616368650A00676574636C75737420616439 +S3250001DED064722025640A0063616E2774207365656B20626C6F636B0A0063616E2774207279 +S3250001DEF065616420626C6F636B0A00676574636C75737420256420726561640A0066617497 +S3250001DF1077616C6B2025640A006765746661740066617477616C6B202564202D3E20256446 +S3250001DF300A0066696C65616464722025382E38732025640A0066696C656164647220256498 +S3250001DF50202D3E2025640A0066696C6561646472202564202D3E2025640A0077616C6B6932 +S3250001DF706E67206E6F6E2D6469726563746F7279210A00636F6D706172696E6720746F203A +S3250001DF9025382E38732E25332E33730A0025382E38732E25332E33732069732061204C4116 +S3250001DFB042454C0A0063616E2774207265616420626F6F7420626C6F636B0A006E6F74206A +S3250001DFD0444F530A006E6F20646F732066696C652073797374656D0A006D616769633A200D +S3250001DFF0307825322E327820307825322E327820307825322E32780A0076657273696F6E35 +S3250001E0103A202225382E3873220A007365637473697A653A2025640A00616C6C6F637369CD +S3250001E0307A653A2025640A006E72657372763A2025640A006E666174733A2025640A0072F5 +S3250001E0506F6F7473697A653A2025640A00766F6C73697A653A2025640A006D656469616452 +S3250001E0706573633A20307825322E32780A0066617473697A653A2025640A0074726B736903 +S3250001E0907A653A2025640A006E68656164733A2025640A006E68696464656E3A2025640A76 +S3250001E0B000626967766F6C73697A653A2025640A0064726976656E6F3A2025640A00726563 +S3250001E0D0736572766564303A20307825322E32780A00626F6F747369673A20307825322EB7 +S3250001E0F032780A00766F6C69643A20307825382E38780A006C6162656C3A20222531312EBF +S3250001E110313173220A006E616D6520636F6D706F6E656E7420746F6F206C6F6E670A0065A2 +S3250001E13072726F722077616C6B696E6720746F2025730A002573206E6F7420666F756E64EC +S3250001E1500A00666F756E642025382E38732E25332E3373206174747220307825757820738A +S3250001E17074617274203078256C7578206C656E2025640A00626164206D6167696320307865 +S3250001E190256C7578206E6F74206120706C616E20392065786563757461626C65210A002B3C +S3250001E1B02564002B2564002B25640A7374617274206174203078256C75780A002E006E61DD +S3250001E1D06D652069732025382E38732025332E33730A0000000000002E007A71733A206E5A +S3250001E1F06F7420706F77657250432065786563757461626C650A0074657874007A71733A9C +S3250001E21020666F726D6174206572726F720A0064617461007A71733A20666F726D617420EF +S3250001E2306572726F720A000A73717565657A6564206B65726E656C3A20636865636B737542 +S3250001E2506D206572726F723A2025382E386C7578206E6565642025382E386C75780A007503 +S3250001E2706E7061636B2025732025382E386C757820256C75643A00202A2A73697A6520650E +S3250001E29072726F720A000A007A71733A20636F72727570742073717565657A65642064615C +S3250001E2B074612073747265616D0A00205425640025642025382E386C75782025382E386CAB +S3250001E2D075780A0000000000666C6173683A2062616420636865636B73756D0A00666C61F1 +S3250001E2F073683A20666C617368206E6F742070726573656E74206F72206E6F7420656E616C +S3250001E310626C65640A00636F6E66202325382E386C75783A20232578202325362E366C7543 +S3250001E330780A00666C6173683A20666F756E6420636F6E6669672025382E386C75782825A1 +S3250001E35064293A0A25730A00666C6173683A206E6F20636F6E6669670A00666C6173682020 +S3250001E370636F6E6669672025382E386C7578282564293A0A25730A00666C6173683A207339 +S3250001E390717565657A656420706F7765727063206B65726E656C20696E7374616C6C6564D2 +S3250001E3B00A00666C6173683A20756E73717565657A656420706F7765727063206B65726E9B +S3250001E3D0656C20696E7374616C6C65640A00666C6173683A206E6F20706F776572706320E6 +S3250001E3F06B65726E656C20696E20466C6173680A00746578743A2025382E386C7578203CDF +S3250001E4102D2025382E386C7578205B256C645D0A00646174613A2025382E386C7578203C39 +S3250001E4302D2025382E386C7578205B256C645D0A00656E7472793D3078256C75780A0000E6 +S3250001E450907070F0F0F07000F0888888F8707070E0E0E0E0E09070F070F870F0F870F0882D +S3250001E470000000000000000000000000000000000000000000000000000000000000000085 +S3250001E490000000000000000000000000000000000000000000000000000000000000000065 +S3250001E4B000000000000000000000000000000000000000000000000000000000000000E065 +S3250001E4D0D0808080808088008888C888808888889090909090D0808080808080808888881D +S3250001E4F000000000080000000C3000000000000600000000000000000000000000000000BB +S3250001E5100000000000000000000000000000000000000000000000000000003CC03C0000AC +S3250001E5300000600006001E00601818607800000000000000000000000000001C18380090DC +S3250001E550B06060E0E0E0F800F088A888808080809090909090B060E0808060E080808888E4 +S3250001E570001824283E70701818180000000000063C183C3C1C3E3C7E3C3C00000200403CDE +S3250001E5903C187C1E787E7E1E663C7C666066623C7C3C7C3C7E6266C266667E30C00C10002E +S3250001E5B008006000060030006018186018000000000000001000000000000030180C0090AA +S3250001E5D0901010808080881888F8A888E0807070E0E0E0E0E090108070E01080E098F08814 +S3250001E5F0001824286ADAD818181810000000000C663866662C3E667E6666000006006066D0 +S3250001E610421866326C606032661818646066722466246666186262DA62620630600C380093 +S3250001E63010006000060030006000006018000000000000003000000000000030180C00E0E1 +S3250001E65000E0E0F0F0F000188888985080880808201C1C1C1C00E0F00080E0F08088888823 +S3250001E6700018242868DAD808300C54180000000C665806062C206002666618180CFE300695 +S3250001E6909E2C6660666060606618186C6066726666666660186262DA36660C30600C2800F9 +S3250001E6B0103C6C3C3E3C7E3E6C78786618D46C3C6C3E763C7E6666C266667E1818180000C9 +S3250001E6D04418000018241C24F08888208070F0F020202020201C243E1CF8241C8070887001 +S3250001E6F00018247C78745008300C381800000018661806064C2060067666181818FE180CC1 +S3250001E710B62C66606660606066181868607E5A6666666470186266DA34340C30300C6C0072 +S3250001E73018667666666630667618186418FE766676663666306662DA626206081810323C58 +S3250001E75044247C7C2434204200000000000000002020202020222408220024200000000034 +S3250001E770001800283C287610300CEE7E00FE001866180C184C3C7C0C3C3E000030000C181A +S3250001E790B62C7C60667C7C6E7E181878605A5A666466783C186234DA18341830300C44001E +S3250001E7B018066660666630666618186818D6666666663860306662DA34620C30180C5A209E +S3250001E7D044241010242C20420E3E103E3E3C1C3E3C1C1C1C1C3E1C083E2224180E0E0E0E98 +S3250001E7F00008007C1E5CDC00300C387E00FE0030661818067E0666186E06000018001818AE +S3250001E810B67E6660666060666618186C605A4E6678666C0E1862346C2C183030180C44006D +S3250001E830003E6660667E30666618187818D666666666303C306634DA1834180818104C3887 +S3250001E8503C18101018241C4211081008202222080000000000220408223618041111111110 +S3250001E8700000002816B6CC00300C541800000030661830067E066618660600000CFE30008D +S3250001E8909A466660666060666618186C605A4E66606666061862346C6C183030180C00006B +S3250001E8B000666660666030666618186C18D66666666630063066346C2C34301818180020CD +S3250001E8D000091010000E094210081008202222080F06060F0A09041E002A0E3810101010F4 +S3250001E8F00018002856B6CC00300C10181800186066187E660C6666306666181806FE601813 +S3250001E910404666326C60603666181866605A4624602466661834186C461860300C0C00001A +S3250001E930006E66666E66306E6618186618D66666666E3066306E186C46186030180C003C84 +S3250001E950080909091F110AFF0E081008382C2208080209010A0A0911092209070E0E0E0ED3 +S3250001E970001800287C1C760018180000180018603C7E7E3C0C3C3C303C3C18180200401848 +S3250001E9903E467C1E787E601E663C18667E42463C603C663C1818186C66187E300C0C000036 +S3250001E9B000367C3C363C7C36667E18667ED6663C7C367C3C1E36186C66187E30180C00083C +S3250001E9D0080F060604110C1801081008202222080E0202030A0C0D1E0D220E080101010198 +S3250001E9F0000000001000000018180000080000C000000000000000000000000800000000F0 +S3250001EA1000000000000000000000180000000000000C00000000000000000030060C00FE7B +S3250001EA300000000000000006000018000000000060060000000000000010001C18380008B7 +S3250001EA5008090606040E0A1811081F0820221C3E080204010F0A0B110B22090811111111AC +S3250001EA7000000000000000000C300000080000C00000000000000000000000080000000073 +S3250001EA900000000000000000000070000000000000060000000000000000003C063C00006B +S3250001EAB0000000000000006600001800000000006006000000000000003000000000000823 +S3250001EAD00F090909040309000E000000000000000F0F0F0F0209091E09000F070E0E0E0E12 +S3250001EAF00000000000000000000000001000000000000000000000000000001000000000DF +S3250001EB100000000000000000000000000000000000000000000000000000000000000000DE +S3250001EB30000000000000003C00007000000000006006000000000000006000000000000F3D +S3250001EB50636F6E736F6C65006C63640073637265656E006C63640062617564005E70002536 +S3250001EB70735B64656661756C743D3D25735D3A200025733A20000A006C696E6520746F6FEC +S3250001EB90206C6F6E670A0070616E69633A20000A0000000000000000001406200014062B96 +S3250001EBB000140638001406460014065200140665001406780014068200140694001406AFFC +S3250001EBD0001406BB001406C6001406D1001406DD001406E8001406FE001407090014071C12 +S3250001EBF000140726001407300014073B000000000000000E000800000008000E00080000E8 +S3250001EC100010000E000800000018000E000800000020000E000800000028000E0008000015 +S3250001EC300030000E000800000038000E000800000040000E000800000048000E0008000075 +S3250001EC500050000E000800000058000E000800000060000E000800000068000E00080000D5 +S3250001EC700070000E000800000078000E000800000080000E000800000088000E0008000035 +S3250001EC900090000E000800000098000E0008000000A0000E0008000000A8000E0008000095 +S3250001ECB000B0000E0008000000B8000E0008000000C0000E0008000000C8000E00080000F5 +S3250001ECD000D0000E0008000000D8000E0008000000E0000E0008000000E8000E0008000055 +S3250001ECF000F0000E0008000000F8000E0008000001000000000800000108020B00080000C2 +S3250001ED1001100206000800000118020B000800000120010C000800000128020B0008000019 +S3250001ED300130020B0008000001380207000800000140010D000800000148010D0008000076 +S3250001ED500150030A000800000158040A000800000160090E000800000168060800080000C8 +S3250001ED700170090B000800000178010D000800000180020B000800000188020B000800002C +S3250001ED900190020B000800000198020B0008000001A0020B0008000001A8020B0008000094 +S3250001EDB001B0020B0008000001B8020B0008000001C0020B0008000001C8020B00080000F4 +S3250001EDD001D0040B0008000001D8040E0008000001E0020B0008000001E8040A000800004C +S3250001EDF001F0020B0008000001F8020B000800000200020B000800000208020B00080000B2 +S3250001EE100210020B000800000218020B000800000220020B000800000228020B000800000F +S3250001EE300230020B000800000238020B000800000240020B000800000248020B000800006F +S3250001EE500250020D000800000258020B000800000260020B000800000268020B00080000CD +S3250001EE700270020B000800000278020B000800000280020B000800000288020D000800002D +S3250001EE900290020B000800000298020B0008000002A0020B0008000002A8020B000800008F +S3250001EEB002B0020B0008000002B8020B0008000002C0020B0008000002C8020B00080000EF +S3250001EED002D0020B0008000002D8010D0008000002E0010D0008000002E8010D000800004C +S3250001EEF002F002080008000002F80B0C0008000003000207000800000308040B00080000A8 +S3250001EF100310010B000800000318040B000800000320010B000800000328040B0008000008 +S3250001EF300330010B000800000338040E000800000340010B000800000348010B0008000068 +S3250001EF500350010E000800000358010B000800000360010B000800000368040B00080000C8 +S3250001EF700370040B000800000378040B000800000380040E000800000388040E000800001C +S3250001EF900390040B000800000398040B0008000003A0020B0008000003A8040B0008000084 +S3250001EFB003B0040B0008000003B8040B0008000003C0040B0008000003C8040E00080000DF +S3250001EFD003D0040B0008000003D8010C0008000003E0010C0008000003E8010C0008000048 +S3250001EFF003F005080008000003F8000E000800000400000E000800000000000000000000C7 +S3250001F010534343005343433200657468657225643A2025733A20706F7274203078256C7575 +S3250001F0305820697271202564002061646472203078256C7558002073697A65203078256C37 +S3250001F0507558003A002025322E327558000A00657468657225643A207478207175657565B8 +S3250001F0702066756C6C0A0000666C6173680046006574686572006500617461006864006861 +S3250001F090006175746F006C6F63616C006D616E75616C00696E6665726E6F2F696E666572E3 +S3250001F0B06E6F2E696E6900696E6665726E6F2E696E6900706C616E392F706C616E392E6901 +S3250001F0D06E6900706C616E392E696E69002100002573212564006469736B002573212564A0 +S3250001F0F0212573006469736B00696D706300257321256421257300626F6F74006469736B92 +S3250001F11000646F73006469736B00646F7320696E6974206661696C65640A00707265646132 +S3250001F130776E0A006461776E0A006F7074696F6E733D232575780A00466C61736820626FAE +S3250001F1506F740A00626F6F7466696C650042616420626F6F7466696C652073796E74617815 +S3250001F1703A2025730A0043616E6E6F7420616363657373206465766963653A2025730A00FB +S3250001F190426F6F7420646576696365733A00202573212564002025732125640020257321EA +S3250001F1B02564000A00626F6F742066726F6D00706879736963616C206D656D6F727900699E +S3250001F1D0616C6C6F63006672656500000000000045544845522E5343432325643A20736310 +S3250001F1F06365203D2030782575580A007E0040006E6F207072657365742045746865722089 +S3250001F210616464726573730A00303031303862663132393030006574686572204D41432001 +S3250001F2306164647265737300696E76616C6964204D414320616464726573730A00000000E9 +S3250001F2500A746674703A206572726F72282564293A2025730A0069702063686B73756D20D1 +S3250001F2706572726F720A0069702062616420766572732F686C656E0A007564702063686BC4 +S3250001F29073756D206572726F72206373756D202325346C7578206C656E2025640A00756400 +S3250001F2B0703A207061636B657420746F6F206269670A002573006F637465740074667470B2 +S3250001F2D06F70656E3A206572726F7220282564293A2025730A00746674706F70656E3A2021 +S3250001F2F0626C6F636B206572726F723A2025640A00626C6F636B206572726F720074667412 +S3250001F310706F70656E3A206661696C656420746F20636F6E6E65637420746F207365727605 +S3250001F33065720A0074667470726561643A20256420213D2025640A0073686F727420726540 +S3250001F3506164003F0074667470726561643A20626C6F636B206572726F723A2025642C205A +S3250001F37065787065637465642025640A00626C6F636B206572726F7200696E76616C696435 +S3250001F3902063746C726E6F2025640A00626F6F74702074696D6564206F75740A0025732060 +S3250001F3B0002825642E25642E25642E2564212564293A2025730A00626164206D6167696349 +S3250001F3D0206E756D626572006C6F61644025382E386C75783A20002564002B2564006F6B00 +S3250001F3F0002B25643D25640A00656E7472793A203078256C75780A000000000000141A6820 +S3250001F41000000008FFC27AE40000000000000000000000000000000000141A6E0000000012 +S3250001F43000000000000000000000000200141A7000000004FFC26068000000000000000088 +S3250001F45000000000000000000000000000141A7600000000000000000000000300141A7848 +S3250001F470000000130000000000000000000000000000000000141A7C00141A7F000000000B +S3250001F4900000000000000000FFFFFFFF000000000000000000000000000000000000000059 +S3250001F4B0000000000000000000000000000000000000000000000000496E6665726E6F2044 +S3250001F4D0626F6F7473747261700A005056523A20004D5043363031004D5043363033004D9E +S3250001F4F05043363034004D504336303365004D5043363033652D7637004D5043387878002A +S3250001F510506F77657250432076657273696F6E20232578002C207265766973696F6E202330 +S3250001F530256C75780A00494D4D523A20004D50433836302F383231004D5043383233004D8B +S3250001F55050433832334100547970652023256C7578002C206D61736B2023256C75780A00FD +S3250001F5706F7074696F6E733A2023256C75780A00626373723A2025382E386C75780A0050E9 +S3250001F5904C505243523D25382E386C757820534343523D25382E386C75780A00256C756460 +S3250001F5B0204D487A2073797374656D0A000A004252303D25382E386C7578204F52303D25BC +S3250001F5D0382E386C75780A004D505450523D25382E386C75780A006574686572303D7479AB +S3250001F5F070653D53434320706F72743D312065613D3030313065633030303035310D0A7657 +S3250001F610676173697A653D3634307834383078380D0A6B65726E656C70657263656E743DEF +S3250001F63034300D0A636F6E736F6C653D300D0A626175643D393630300D0A006574686572EA +S3250001F650303D747970653D53434320706F72743D322065613D303031306563303030303559 +S3250001F670310D0A76676173697A653D3634307834383078380D0A6B65726E656C7065726355 +S3250001F690656E743D34300D0A636F6E736F6C653D300D0A626175643D393630300D0A0055C9 +S3250001F6B073696E672064656661756C7420636F6E66696775726174696F6E0A00414D4432D7 +S3250001F6D039463078300053434300454100693263206661696C65640A00656570726F6D3A0E +S3250001F6F00A002025322E3275785B25635D000A00CFFFCC240FFFCC040CAFCC0403AFCC082E +S3250001F7103FBFCC27FFFFCC25FFFFCC25FFFFCC25CFFFCC240FFFCC040CAFCC8403AFCC8867 +S3250001F7303FBFCC27FFFFCC25FFFFCC25FFFFCC25FFFFCC25FFFFCC25FFFFCC25FFFFCC2538 +S3250001F750FFFFCC25FFFFCC25FFFFCC25FFFFCC25CFFFCC240FFFCC040CFFCC0403FFCC0091 +S3250001F7703FFFCC27FFFFCC25FFFFCC25FFFFCC25CFFFCC240FFFCC040CFFCC8403FFCC842B +S3250001F7900CFFCC0033FFCC27FFFFCC25FFFFCC25FFFFCC25FFFFCC25FFFFCC25FFFFCC25BC +S3250001F7B0FFFFCC25FFFFCC25FFFFCC25FFFFCC25C0FFCC2403FFCC240FFFCC240FFFCC24D9 +S3250001F7D03FFFCC27FFFFCC25FFFFCC25FFFFCC25FFFFCC25FFFFCC25FFFFCC25FFFFCC2558 +S3150001F7F0FFFFCC25FFFFCC25FFFFCC25FFFFCC2546 +S700000100FE diff --git a/os/boot/rpcg/gbitbltclip.c b/os/boot/rpcg/gbitbltclip.c new file mode 100644 index 00000000..cbf877f5 --- /dev/null +++ b/os/boot/rpcg/gbitbltclip.c @@ -0,0 +1,52 @@ +#include <u.h> +#include <libc.h> +#include <libg.h> +#include <gnot.h> + +void +gbitbltclip(void *vp) +{ + int dx, dy; + int i; + struct{ + GBitmap *dm; + Point p; + GBitmap *sm; + Rectangle r; + Fcode f; + }*bp; + + bp = vp; + dx = Dx(bp->r); + dy = Dy(bp->r); + if(bp->p.x < bp->dm->clipr.min.x){ + i = bp->dm->clipr.min.x-bp->p.x; + bp->r.min.x += i; + bp->p.x += i; + dx -= i; + } + if(bp->p.y < bp->dm->clipr.min.y){ + i = bp->dm->clipr.min.y-bp->p.y; + bp->r.min.y += i; + bp->p.y += i; + dy -= i; + } + if(bp->p.x+dx > bp->dm->clipr.max.x) + bp->r.max.x -= bp->p.x+dx-bp->dm->clipr.max.x; + if(bp->p.y+dy > bp->dm->clipr.max.y) + bp->r.max.y -= bp->p.y+dy-bp->dm->clipr.max.y; + if(bp->r.min.x < bp->sm->clipr.min.x){ + i = bp->sm->clipr.min.x-bp->r.min.x; + bp->p.x += i; + bp->r.min.x += i; + } + if(bp->r.min.y < bp->sm->clipr.min.y){ + i = bp->sm->clipr.min.y-bp->r.min.y; + bp->p.y += i; + bp->r.min.y += i; + } + if(bp->r.max.x > bp->sm->clipr.max.x) + bp->r.max.x = bp->sm->clipr.max.x; + if(bp->r.max.y > bp->sm->clipr.max.y) + bp->r.max.y = bp->sm->clipr.max.y; +} diff --git a/os/boot/rpcg/gnot.h b/os/boot/rpcg/gnot.h new file mode 100644 index 00000000..7b99e6bb --- /dev/null +++ b/os/boot/rpcg/gnot.h @@ -0,0 +1,71 @@ + +extern void *bbmalloc(int); +extern void bbfree(void *, int); +extern int bbonstack(void); +extern void bbexec(void(*)(void), int, int); + +/* + * Graphics types + */ + +typedef struct GBitmap GBitmap; +typedef struct GFont GFont; +typedef struct GSubfont GSubfont; +typedef struct GCacheinfo GCacheinfo; + +struct GBitmap +{ + ulong *base; /* pointer to start of data */ + long zero; /* base+zero=&word containing (0,0) */ + ulong width; /* width in 32 bit words of total data area */ + int ldepth; /* log base 2 of number of bits per pixel */ + Rectangle r; /* rectangle in data area, local coords */ + Rectangle clipr; /* clipping region */ + GBitmap *cache; /* zero; distinguishes bitmap from layer */ +}; + + +/* + * GFont etc. are not used in the library, only in devbit.c. + * GSubfont is only barely used. + */ +struct GSubfont +{ + short n; /* number of chars in font */ + char height; /* height of bitmap */ + char ascent; /* top of bitmap to baseline */ + Fontchar *info; /* n+1 character descriptors */ + GBitmap *bits; /* where the characters are */ +}; +struct GCacheinfo +{ + ulong xright; /* right edge of bits */ + Fontchar; +}; + +struct GFont +{ + uchar height; /* max height of bitmap, interline spacing */ + char ascent; /* top of bitmap to baseline */ + char width; /* widest so far; used in caching only */ + char ldepth; /* of images */ + short id; /* of font */ + int ncache; /* number of entries in cache */ + GCacheinfo *cache; /* cached characters */ + GBitmap *b; /* cached images */ +}; + +extern ulong *gaddr(GBitmap*, Point); +extern uchar *gbaddr(GBitmap*, Point); +extern void gbitblt(GBitmap*, Point, GBitmap*, Rectangle, Fcode); +extern void gbitbltclip(void*); +extern void gtexture(GBitmap*, Rectangle, GBitmap*, Fcode); +extern Point gsubfstrsize(GSubfont*, char*); +extern int gsubfstrwidth(GSubfont*, char*); +extern Point gsubfstring(GBitmap*, Point, GSubfont*, char*, Fcode); +extern Point gbitbltstring(GBitmap*, Point, GSubfont*, char*, Fcode); +extern void gsegment(GBitmap*, Point, Point, int, Fcode); +extern void gpoint(GBitmap*, Point, int, Fcode); +extern void gflushcpucache(void); +extern GBitmap* gballoc(Rectangle, int); +extern void gbfree(GBitmap*); diff --git a/os/boot/rpcg/i2c.c b/os/boot/rpcg/i2c.c new file mode 100644 index 00000000..dfd07fa8 --- /dev/null +++ b/os/boot/rpcg/i2c.c @@ -0,0 +1,360 @@ +#include "boot.h" + +/* + * basic read/write interface to mpc8xx I2C bus (master mode) + */ + +typedef struct I2C I2C; + +struct I2C { + uchar i2mod; + uchar rsv12a[3]; + uchar i2add; + uchar rsv12b[3]; + uchar i2brg; + uchar rsv12c[3]; + uchar i2com; + uchar rsv12d[3]; + uchar i2cer; + uchar rsv12e[3]; + uchar i2cmr; +}; + +enum { + /* i2c-specific BD flags */ + RxeOV= 1<<1, /* overrun */ + TxS= 1<<10, /* transmit start condition */ + TxeNAK= 1<<2, /* last transmitted byte not acknowledged */ + TxeUN= 1<<1, /* underflow */ + TxeCL= 1<<0, /* collision */ + TxERR= (TxeNAK|TxeUN|TxeCL), + + /* i2cmod */ + REVD= 1<<5, /* =1, LSB first */ + GCD= 1<<4, /* =1, general call address disabled */ + FLT= 1<<3, /* =0, not filtered; =1, filtered */ + PDIV= 3<<1, /* predivisor field */ + EN= 1<<0, /* enable */ + + /* i2com */ + STR= 1<<7, /* start transmit */ + I2CM= 1<<0, /* master */ + I2CS= 0<<0, /* slave */ + + /* i2cer */ + TXE = 1<<4, + BSY = 1<<2, + TXB = 1<<1, + RXB = 1<<0, + + /* port B bits */ + I2CSDA = IBIT(27), + I2CSCL = IBIT(26), + + Rbit = 1<<0, /* bit in address byte denoting read */ + + /* maximum I2C I/O (can change) */ + MaxIO= 128, + Bufsize = MaxIO+4, /* extra space for address/clock bytes and alignment */ + Freq = 100000, + I2CTimeout = 250, /* msec */ +}; + +/* data cache needn't be flushed if buffers allocated in uncached INTMEM */ +#define DCFLUSH(a,n) + +/* + * I2C software structures + */ + +struct Ctlr { + Lock; + QLock io; + int init; + I2C* i2c; + IOCparam* sp; + + BD* rd; + BD* td; + int phase; + int timeout; + char* addr; + char* txbuf; + char* rxbuf; +}; +typedef struct Ctlr Ctlr; + +static Ctlr i2ctlr[1]; +extern int predawn; + +static void interrupt(Ureg*, void*); + +static void +enable(void) +{ + I2C *i2c; + + i2c = i2ctlr->i2c; + i2c->i2cer = ~0; /* clear events */ + eieio(); + i2c->i2mod |= EN; + eieio(); + i2c->i2cmr = TXE|BSY|TXB|RXB; /* enable all interrupts */ + eieio(); +} + +static void +disable(void) +{ + I2C *i2c; + + i2c = i2ctlr->i2c; + i2c->i2cmr = 0; /* mask all interrupts */ + i2c->i2mod &= ~EN; +} + +/* + * called by the reset routine of any driver using the I2C + */ +void +i2csetup(void) +{ + IMM *io; + I2C *i2c; + IOCparam *sp; + Ctlr *ctlr; + long f, e, emin; + int p, d, dmax; + + ctlr = i2ctlr; + if(ctlr->init) + return; + print("i2c setup...\n"); + ctlr->init = 1; + i2c = KADDR(INTMEM+0x860); + ctlr->i2c = i2c; + sp = KADDR(INTMEM+0x3c80); + ctlr->sp = sp; + disable(); + + if(ctlr->txbuf == nil){ + ctlr->txbuf = ialloc(Bufsize, 2); + ctlr->addr = ctlr->txbuf+Bufsize; + } + if(ctlr->rxbuf == nil) + ctlr->rxbuf = ialloc(Bufsize, 2); + if(ctlr->rd == nil){ + ctlr->rd = bdalloc(1); + ctlr->rd->addr = PADDR(ctlr->rxbuf); + ctlr->rd->length = 0; + ctlr->rd->status = BDWrap; + } + if(ctlr->td == nil){ + ctlr->td = bdalloc(2); + ctlr->td->addr = PADDR(ctlr->txbuf); + ctlr->td->length = 0; + ctlr->td->status = BDWrap|BDLast; + } + + /* select port pins */ + io = ioplock(); + io->pbdir |= I2CSDA | I2CSCL; + io->pbodr |= I2CSDA | I2CSCL; + io->pbpar |= I2CSDA | I2CSCL; + iopunlock(); + + /* explicitly initialise parameters, because InitRxTx can't be used (see i2c/spi relocation errata) */ + sp = ctlr->sp; + sp->rbase = PADDR(ctlr->rd); + sp->tbase = PADDR(ctlr->td); + sp->rfcr = 0x18; + sp->tfcr = 0x18; + sp->mrblr = Bufsize; + sp->rstate = 0; + sp->rptr = 0; + sp->rbptr = sp->rbase; + sp->rcnt = 0; + sp->tstate = 0; + sp->tbptr = sp->tbase; + sp->tptr = 0; + sp->tcnt = 0; + eieio(); + + i2c->i2com = I2CM; + i2c->i2mod = 0; /* normal mode */ + i2c->i2add = 0; + + emin = Freq; + dmax = (m->cpuhz/Freq)/2-3; + for(d=0; d < dmax; d++){ + for(p=3; p>=0; p--){ + f = (m->cpuhz>>(p+2))/(2*(d+3)); + e = Freq - f; + if(e < 0) + e = -e; + if(e < emin){ + emin = e; + i2c->i2brg = d; + i2c->i2mod = (i2c->i2mod&~PDIV)|((3-p)<<1); /* set PDIV */ + } + } + } + //print("i2brg=%d i2mod=#%2.2ux\n", i2c->i2brg, i2c->i2mod); + setvec(VectorCPIC+0x10, interrupt, i2ctlr); +} + +enum { + Idling, + Done, + Busy, + Sending, + Recving, +}; + +static void +interrupt(Ureg*, void *arg) +{ + int events; + Ctlr *ctlr; + I2C *i2c; + + ctlr = arg; + i2c = ctlr->i2c; + events = i2c->i2cer; + eieio(); + i2c->i2cer = events; + if(events & (BSY|TXE)){ + print("I2C#%x\n", events); + if(ctlr->phase != Idling){ + ctlr->phase = Idling; + } + }else{ + if(events & TXB){ + //print("i2c: xmt %d %4.4ux %4.4ux\n", ctlr->phase, ctlr->td->status, ctlr->td[1].status); + if(ctlr->phase == Sending){ + ctlr->phase = Done; + } + } + if(events & RXB){ + //print("i2c: rcv %d %4.4ux %d\n", ctlr->phase, ctlr->rd->status, ctlr->rd->length); + if(ctlr->phase == Recving){ + ctlr->phase = Done; + } + } + } +} + +static int +done(void *a) +{ + return ((Ctlr*)a)->phase < Busy; +} + +static void +i2cwait(Ctlr *ctlr) +{ + int i; + + ctlr->timeout = 0; + i = 0; + while(!done(ctlr)){ + if(predawn){ + if(++i > 100){ + ctlr->phase = Done; + ctlr->timeout = 1; + return; + } + delay(1); + interrupt(nil, ctlr); + } + } +} + +long +i2csend(int addr, void *buf, long n) +{ + Ctlr *ctlr; + int i, p, s; + + ctlr = i2ctlr; + if(n > MaxIO) + return -1; + i = 1; + ctlr->txbuf[0] = addr & ~1; + if(addr & 1){ + ctlr->txbuf[1] = addr>>8; + i++; + } + memmove(ctlr->txbuf+i, buf, n); + DCFLUSH(ctlr->txbuf, Bufsize); + ctlr->phase = Sending; + ctlr->rd->status = BDEmpty|BDWrap|BDInt; + ctlr->td->addr = PADDR(ctlr->txbuf); + ctlr->td->length = n+i; + ctlr->td->status = BDReady|BDWrap|BDLast|BDInt; + enable(); + ctlr->i2c->i2com = STR|I2CM; + eieio(); + i2cwait(ctlr); + disable(); + p = ctlr->phase; + s = ctlr->td->status; + if(s & BDReady || s & TxERR || p != Done || ctlr->timeout) + return -1; + return n; +} + +long +i2crecv(int addr, void *buf, long n) +{ + Ctlr *ctlr; + int p, s, flag; + BD *td; + long nr; + + ctlr = i2ctlr; + if(n > MaxIO) + return -1; + ctlr->txbuf[0] = addr|Rbit; + if(addr & 1){ /* special select sequence */ + ctlr->addr[0] = addr &~ 1; + ctlr->addr[1] = addr>>8; + } + DCFLUSH(ctlr->txbuf, Bufsize); + DCFLUSH(ctlr->rxbuf, Bufsize); + ctlr->phase = Recving; + ctlr->rd->addr = PADDR(ctlr->rxbuf); + ctlr->rd->status = BDEmpty|BDWrap|BDInt; + flag = 0; + td = ctlr->td; + td[1].status = 0; + if(addr & 1){ + /* special select sequence */ + td->addr = PADDR(ctlr->addr); + td->length = 2; + /* td->status made BDReady below */ + td++; + flag = TxS; + } + td->addr = PADDR(ctlr->txbuf); + td->length = n+1; + td->status = BDReady|BDWrap|BDLast | flag; /* not BDInt: leave that to receive */ + if(flag) + ctlr->td->status = BDReady; + enable(); + ctlr->i2c->i2com = STR|I2CM; + eieio(); + i2cwait(ctlr); + disable(); + p = ctlr->phase; + s = ctlr->td->status; + if(flag) + s |= ctlr->td[1].status; + nr = ctlr->rd->length; + if(nr > n) + nr = n; /* shouldn't happen */ + if(s & TxERR || s & BDReady || p != Done || ctlr->rd->status & BDEmpty || ctlr->timeout) + return -1; + memmove(buf, ctlr->rxbuf, nr); + return nr; +} diff --git a/os/boot/rpcg/initfads.c b/os/boot/rpcg/initfads.c new file mode 100644 index 00000000..eed7c319 --- /dev/null +++ b/os/boot/rpcg/initfads.c @@ -0,0 +1,187 @@ +/* + * Called from l.s in EPROM to set up a minimal working environment. + * Since there is no DRAM yet, and therefore no stack, no function + * calls may be made from sysinit0, and values can't be stored, + * except to INTMEM. Global values are accessed by offset from SB, + * which has been set by l.s to point into EPROM. + * + * This is FADS-specific in CS assignment and access of the FADS BCSR + * to discover memory size and speed. + */ + +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" + +#include "archfads.h" + +#define MB (1024*1024) + +enum { + UPMSIZE = 64, /* memory controller instruction RAM */ + SPEED = 50, /* maximum memory clock in MHz */ + SDRAMSIZE = 4*MB, + + /* mcr */ + WriteRAM = 0<<30, + ReadRAM = 1<<30, + ExecRAM = 2<<30, + + SelUPMA = 0<<23, + SelUPMB = 1<<23, + + Once = 1<<8, +}; + +/* + * mpc8bug uses the following for 60ns EDO DRAMs 32-50MHz + */ +static ulong upma50[UPMSIZE] = { + 0x8FFFEC24, 0xFFFEC04, 0xCFFEC04, 0xFFEC04, + 0xFFEC00, 0x37FFEC47, 0xFFFFFFFF, 0xFFFFFFFF, + 0x8FFFEC24, 0xFFFEC04, 0x8FFEC04, 0xFFEC0C, + 0x3FFEC00, 0xFFEC44, 0xFFCC08, 0xCFFCC44, + 0xFFEC0C, 0x3FFEC00, 0xFFEC44, 0xFFCC00, + 0x3FFFC847, 0x3FFFEC47, 0xFFFFFFFF, 0xFFFFFFFF, + 0x8FAFCC24, 0xFAFCC04, 0xCAFCC00, 0x11BFCC47, + 0xC0FFCC84, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0x8FAFCC24, 0xFAFCC04, 0xCAFCC00, 0x3AFCC4C, + 0xCAFCC00, 0x3AFCC4C, 0xCAFCC00, 0x3AFCC4C, + 0xCAFCC00, 0x33BFCC4F, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xC0FFCC84, 0xFFCC04, 0x7FFCC04, 0x3FFFCC06, + 0xFFFFCC85, 0xFFFFCC05, 0xFFFFCC05, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0x33FFCC07, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, +}; + +/* + * the FADS manual table 3-7 suggests the following for 60ns EDO DRAMs at 20MHz + */ +static ulong upma20[UPMSIZE] = { + 0x8FFFCC04, 0x08FFCC00, 0x33FFCC47, ~0, ~0, ~0, ~0, ~0, + [0x08] 0x8FFFCC04, 0x08FFCC08, 0x08FFCC08, 0x08FFCC08, 0x08FFCC00, 0x3FFFCC47, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, + [0x18] 0x8FEFCC00, 0x39BFCC47, ~0, ~0, ~0, ~0, ~0, ~0, + [0x20] 0x8FEFCC00, 0x09AFCC48, 0x09AFCC48, 0x08AFCC48, 0x39BFCC47, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, + [0x30] 0x80FFCC84, 0x17FFCC04, 0xFFFFCC86, 0xFFFFCC05, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, + [0x3C] 0x33FFCC07, ~0, ~0, ~0, +}; + +void +sysinit0(int inrom) +{ + ulong *upm, *bcsr; + IMM *io; + int i, mb; + + io = (IMM*)INTMEM; /* running before maps, no KADDR */ + + /* system interface unit initialisation, FADS manual table 3-2, except as noted */ + io->siumcr = 0x01012440; + io->sypcr = 0xFFFFFF88; + io->tbscrk = KEEP_ALIVE_KEY; + io->tbscr = 0xC3; /* time base enabled */ + io->rtcsck = KEEP_ALIVE_KEY; + io->rtcsc = 0xC1; /* don't FRZ, real-time clock enabled */ + io->rtcsck = ~KEEP_ALIVE_KEY; + io->piscrk = KEEP_ALIVE_KEY; + io->piscr = 0x82; + + io->memc[BCSRCS].option = 0xFFFF8110; /* 32k block, all types access, CS early negate, 1 ws */ + io->memc[BCSRCS].base = BCSRMEM | 1; /* base, 32-bit port, no parity, GPCM */ + + io->memc[BOOTCS].base = FLASHMEM | 1; + io->memc[BOOTCS].option = 0xFF800D54; + + if(!inrom) + return; /* can't initialise DRAM controller from DRAM */ + + bcsr = (ulong*)BCSRMEM; +// bcsr[1] &= ~DisableDRAM; + /* could check DRAM speed here; assume 60ns */ + switch((bcsr[2]>>23)&3){ + default: return; /* can't happen; for the compiler */ + case 0: mb = 4; break; + case 1: mb = 32; break; + case 2: mb = 16; break; + case 3: mb = 8; break; + } + + upm = upma50; + for(i=0; i<UPMSIZE; i++){ + io->mdr = upm[i]; + io->mcr = WriteRAM | SelUPMA | i; + } + io->mptpr = 0x0400; + if(SPEED >= 32) + io->mamr = (0x9C<<24) | 0xA21114; /* 50MHz BRGCLK; FADS manual says 0xC0, mpc8bug sets 0x9C */ + else if(SPEED >= 20) + io->mamr = (0x60<<24) | 0xA21114; /* 25MHz BRGCLK */ + else + io->mamr = (0x40<<24) | 0xA21114; /* 16.67MHz BRGCLK */ + io->memc[DRAM1].option = ~((mb<<20)-1)|0x0800; /* address mask, SAM=1 */ + io->memc[DRAM1].base = 0 | 0x81; /* base at 0, 32-bit port size, no parity, UPMA */ +} + +/* + * the FADS manual table 3-9's suggestion for MB811171622A-100 32+MHz-50MHz + */ +static ulong upmb50[UPMSIZE] = { + [0x00] 0x1F07FC04, 0xEEAEFC04, 0x11ADFC04, 0xEFBBBC00, 0x1FF77C47, + [0x05] 0x1FF77C34, 0xEFEABC34, 0x1FB57C35, + [0x08] 0x1F07FC04, 0xEEAEFC04, 0x10ADFC04, 0xF0AFFC00, 0xF0AFFC00, 0xF1AFFC00, 0xEFBBBC00, 0x1FF77C47, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, + [0x18] 0x1F27FC04, 0xEEAEBC00, 0x01B93C04, 0x1FF77C47, ~0, ~0, ~0, ~0, + [0x20] 0x1F07FC04, 0xEEAEBC00, 0x10AD7C00, 0xF0AFFC00, 0xF0AFFC00, 0xE1BBBC04, 0x1FF77C47, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, + [0x30] 0x1FF5FC84, 0xFFFFFC04, 0xFFFFFC04, 0xFFFFFC04, 0xFFFFFC84, 0xFFFFFC07, ~0, ~0, ~0, ~0, ~0, ~0, + [0x3C] 0x7FFFFC07, ~0, ~0, ~0, +}; + +/* + * the FADS manual table 3-8's suggestion for MB811171622A-100 up to 32MHz + */ +static ulong upmb32[UPMSIZE] = { + [0x00] 0x126CC04, 0xFB98C00, 0x1FF74C45, ~0, ~0, + [0x05] 0x1FE77C34, 0xEFAABC34, 0x1FA57C35, + [0x08] 0x0026FC04, 0x10ADFC00, 0xF0AFFC00, 0xF1AFFC00, 0xEFBBBC00, 0x1FF77C45, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, + [0x18] 0x0E26BC04, 0x01B93C00, 0x1FF77C45, ~0, ~0, ~0, ~0, ~0, + [0x20] 0x0E26BC00, 0x10AD7C00, 0xF0AFFC00, 0xF0AFFC00, 0xE1BBBC04, 0x1FF77C45, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, + [0x30] 0x1FF5FC84, 0xFFFFFC04, 0xFFFFFC84, 0xFFFFFC05, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, + [0x3C] 0x7FFFFC07, ~0, ~0, ~0, +}; + +/* + * optionally called by archfads.c:/^archinit to initialise access to SDRAM + */ +void +sdraminit(ulong base) +{ + ulong *upm; + IMM *io; + int i; + + io = (IMM*)INTMEM; /* running before maps, no KADDR */ + if(SPEED > 32) + upm = upmb50; + else + upm = upmb32; + for(i=0; i<UPMSIZE; i++){ + io->mdr = upm[i]; + io->mcr = WriteRAM | SelUPMB | i; + } + io->memc[SDRAM].option = ~(SDRAMSIZE-1)|0x0A00; /* address mask, SAM=1, G5LS=1 */ + io->memc[SDRAM].base = base | 0xC1; + if(SPEED > 32){ + io->mbmr = 0xD0802114; /* 50MHz BRGCLK */ + io->mar = 0x88; + }else{ + io->mbmr = 0x80802114; /* 32MHz BRGCLK */ + io->mar = 0x48; + } + io->mcr = ExecRAM | SelUPMB | (SDRAM<<13) | Once | 5; /* run MRS command in locations 5-8 of UPMB */ + io->mbmr = (io->mbmr & ~0xF) | 8; + io->mcr = ExecRAM | SelUPMB | (SDRAM<<13) | Once | 0x30; /* run refresh sequence */ + io->mbmr = (io->mbmr & ~0xF) | 4; /* 4-beat refresh bursts */ +} diff --git a/os/boot/rpcg/initpaq.c b/os/boot/rpcg/initpaq.c new file mode 100644 index 00000000..d10d92ce --- /dev/null +++ b/os/boot/rpcg/initpaq.c @@ -0,0 +1,101 @@ +/* + * Called from l.s in EPROM to set up a minimal working environment. + * Since there is no DRAM yet, and therefore no stack, no function + * calls may be made from sysinit0, and values can't be stored, + * except to INTMEM. Global values are accessed by offset from SB, + * which has been set by l.s to point into EPROM. + * + * This is PowerPAQ-specific: + * - assumes 8mbytes + * - powerpaq CS assignment + */ + +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" + +#include "archpaq.h" + +#define MB (1024*1024) + +enum { + DRAMSIZE = 8*MB, + FLASHSIZE = 8*MB, + + UPMSIZE = 64, /* memory controller instruction RAM */ + SPEED = 50, /* maximum memory clock in MHz */ + + /* mcr */ + WriteRAM = 0<<30, + ReadRAM = 1<<30, + ExecRAM = 2<<30, + + SelUPMA = 0<<23, + SelUPMB = 1<<23, + + Once = 1<<8, +}; + +/* + * mpc8bug uses the following for 60ns EDO DRAMs 32-50MHz + */ +static ulong upmb50[UPMSIZE] = { + 0x8FFFEC24, 0xFFFEC04, 0xCFFEC04, 0xFFEC04, + 0xFFEC00, 0x37FFEC47, 0xFFFFFFFF, 0xFFFFFFFF, + 0x8FFFEC24, 0xFFFEC04, 0x8FFEC04, 0xFFEC0C, + 0x3FFEC00, 0xFFEC44, 0xFFCC08, 0xCFFCC44, + 0xFFEC0C, 0x3FFEC00, 0xFFEC44, 0xFFCC00, + 0x3FFFC847, 0x3FFFEC47, 0xFFFFFFFF, 0xFFFFFFFF, + 0x8FAFCC24, 0xFAFCC04, 0xCAFCC00, 0x11BFCC47, + 0xC0FFCC84, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0x8FAFCC24, 0xFAFCC04, 0xCAFCC00, 0x3AFCC4C, + 0xCAFCC00, 0x3AFCC4C, 0xCAFCC00, 0x3AFCC4C, + 0xCAFCC00, 0x33BFCC4F, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xC0FFCC84, 0xFFCC04, 0x7FFCC04, 0x3FFFCC06, + 0xFFFFCC85, 0xFFFFCC05, 0xFFFFCC05, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0x33FFCC07, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, +}; + +void +sysinit0(int inrom) +{ + ulong *upm; + IMM *io; + int i; + + io = (IMM*)INTMEM; /* running before maps, no KADDR */ + + /* system interface unit initialisation, FADS manual table 3-2, except as noted */ + io->siumcr = 0x01012440; + io->sypcr = 0xFFFFFF88; + io->tbscrk = KEEP_ALIVE_KEY; + io->tbscr = 0xC3; /* time base enabled */ + io->rtcsck = KEEP_ALIVE_KEY; + io->rtcsc = 0xC1; /* don't FRZ, real-time clock enabled */ + io->rtcsck = ~KEEP_ALIVE_KEY; + io->piscrk = KEEP_ALIVE_KEY; + io->piscr = 0x82; + + io->memc[BOOTCS].base = FLASHMEM | 1; + io->memc[BOOTCS].option = ~(FLASHSIZE-1)|(1<<8)|(2<<4); /* mask, BIH, 2 wait states */ + + if(!inrom) + return; /* can't initialise DRAM controller from DRAM */ + + /* could check DRAM speed here; assume 60ns */ + /* could probe DRAM for size here; assume DRAMSIZE */ + io->mptpr = 0x400; /* powerpaq flash has 0x1000 */ + io->mbmr = (0xC0<<24) | 0xA21114; /* 50MHz BRGCLK */ + upm = upmb50; + for(i=0; i<UPMSIZE; i++){ + io->mdr = upm[i]; + io->mcr = WriteRAM | SelUPMB | i; + } + io->memc[DRAM1].option = ~(DRAMSIZE-1)|0x0800; /* address mask, SAM=1 */ + io->memc[DRAM1].base = 0 | 0xC1; /* base at 0, 32-bit port size, no parity, UPMB */ +} diff --git a/os/boot/rpcg/initrpcg.c b/os/boot/rpcg/initrpcg.c new file mode 100644 index 00000000..3c69cdd9 --- /dev/null +++ b/os/boot/rpcg/initrpcg.c @@ -0,0 +1,91 @@ + +/* + * Called from l.s in EPROM to set up a minimal working environment. + * Since there is no DRAM yet, and therefore no stack, no function + * calls may be made from sysinit, and values can't be stored, + * except to INTMEM. Global values are accessed by offset from SB, + * which has been set by l.s to point into EPROM. + */ + +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" + +#include "archrpcg.h" + +#define MB (1024*1024) + +enum { + UPMSIZE = 64, /* memory controller instruction RAM */ + DRAMSIZE = 16*MB, + FLASHSIZE = 4*MB, + + WriteRAM = 0<<30, + ReadRAM = 1<<30, + ExecRAM = 2<<30, + + SelUPMA = 0<<23, + SelUPMB = 1<<23, +}; +/* RPCG values for RPXLite AW */ +static ulong upma50[UPMSIZE] = { + 0xCFFFCC24, 0x0FFFCC04, 0x0CAFCC04, 0x03AFCC08, + 0x3FBFCC27, 0xFFFFCC25, 0xFFFFCC25, 0xFFFFCC25, + 0xCFFFCC24, 0x0FFFCC04, 0x0CAFCC84, 0x03AFCC88, + 0x3FBFCC27, 0xFFFFCC25, 0xFFFFCC25, 0xFFFFCC25, + 0xFFFFCC25, 0xFFFFCC25, 0xFFFFCC25, 0xFFFFCC25, + 0xFFFFCC25, 0xFFFFCC25, 0xFFFFCC25, 0xFFFFCC25, + 0xCFFFCC24, 0x0FFFCC04, 0x0CFFCC04, 0x03FFCC00, + 0x3FFFCC27, 0xFFFFCC25, 0xFFFFCC25, 0xFFFFCC25, + 0xCFFFCC24, 0x0FFFCC04, 0x0CFFCC84, 0x03FFCC84, + 0x0CFFCC00, 0x33FFCC27, 0xFFFFCC25, 0xFFFFCC25, + 0xFFFFCC25, 0xFFFFCC25, 0xFFFFCC25, 0xFFFFCC25, + 0xFFFFCC25, 0xFFFFCC25, 0xFFFFCC25, 0xFFFFCC25, + 0xC0FFCC24, 0x03FFCC24, 0x0FFFCC24, 0x0FFFCC24, + 0x3FFFCC27, 0xFFFFCC25, 0xFFFFCC25, 0xFFFFCC25, + 0xFFFFCC25, 0xFFFFCC25, 0xFFFFCC25, 0xFFFFCC25, + 0xFFFFCC25, 0xFFFFCC25, 0xFFFFCC25, 0xFFFFCC25, +}; + +void +sysinit0(int inrom) +{ + ulong *upm; + IMM *io; + int i; + + io = (IMM*)INTMEM; /* running before maps, no KADDR */ +// io->siumcr = 0x01012440; +// io->sypcr = 0xFFFFFF88; + io->tbscrk = KEEP_ALIVE_KEY; + io->tbscr = 0xC3; + io->rtcsck = KEEP_ALIVE_KEY; + io->rtcsc = 0xC1; + io->rtcsck = ~KEEP_ALIVE_KEY; + io->piscrk = KEEP_ALIVE_KEY; + io->piscr = 0x82; +return; + io->memc[BCSRCS].option = 0xFFFF8910; /* 32k block, all types access, CSNT, CS early negate, burst inhibit, 1 ws */ + io->memc[BCSRCS].base = BCSRMEM | 1; /* base, 32-bit port, no parity, GPCM */ + +// io->memc[BOOTCS].base = FLASHMEM | 0x801; /* base, 16 bit port */ +// io->memc[BOOTCS].option = ~(FLASHSIZE-1)|(1<<8)|(4<<4); /* mask, BIH, 4 wait states */ + + if(1||!inrom) + return; /* can't initialise DRAM controller from DRAM */ + + /* TO DO: could check DRAM size and speed now */ + + upm = upma50; + for(i=0; i<nelem(upma50); i++){ + io->mdr = upm[i]; + io->mcr = WriteRAM | SelUPMA | i; + } + io->mptpr = 0x0800; /* divide by 8 */ + io->mamr = (0x58<<24) | 0xA01430; /* 40MHz BRGCLK */ + io->memc[DRAM1].option = ~(DRAMSIZE-1)|0x0E00; /* address mask, SAM=1, G5LA/S=3 */ + io->memc[DRAM1].base = 0 | 0x81; /* base at 0, 32-bit port size, no parity, UPMA */ +} diff --git a/os/boot/rpcg/io.h b/os/boot/rpcg/io.h new file mode 100644 index 00000000..8ae1d5b3 --- /dev/null +++ b/os/boot/rpcg/io.h @@ -0,0 +1,463 @@ +enum +{ + /* software interrupt vectors (SIU and CPM) */ + VectorPIC= 0, /* level 0 to level 7, assigned by software */ + CPIClevel= 4, + VectorIRQ= VectorPIC+8, /* IRQ0 to IRQ7 */ + VectorCPIC= VectorIRQ+8, /* 32 CPM interrupts: 0 (error) to 0x1F (PC15) */ +}; + +enum +{ + BUSUNKNOWN = 0, +}; + +/* + * Buffer Descriptors and IO Rings + */ + +typedef struct BD BD; +struct BD { + ushort status; + ushort length; + ulong addr; +}; + +BD* bdalloc(int); +void bdfree(BD*, int); + +enum { + /* Rx BDs, bits common to all protocols */ + BDEmpty= 1<<15, + BDWrap= 1<<13, + BDInt= 1<<12, + BDLast= 1<<11, + BDFirst= 1<<10, + + /* Tx BDs */ + BDReady= 1<<15, + /* BDWrap, BDInt, BDLast */ +}; + +typedef struct Ring Ring; +struct Ring { + BD* rdr; /* receive descriptor ring */ + void* rrb; /* receive ring buffers */ + int rdrx; /* index into rdr */ + int nrdre; /* length of rdr */ + + BD* tdr; /* transmit descriptor ring */ + Block** txb; /* corresponding transmit ring buffers */ + int tdrh; /* host index into tdr */ + int tdri; /* interface index into tdr */ + int ntdre; /* length of tdr */ + int ntq; /* pending transmit requests */ +}; + +#define NEXT(x, l) (((x)+1)%(l)) +#define PREV(x, l) (((x) == 0) ? (l)-1: (x)-1) +#define HOWMANY(x, y) (((x)+((y)-1))/(y)) +#define ROUNDUP(x, y) (HOWMANY((x), (y))*(y)) + +int ioringinit(Ring*, int, int, int); + +/* + * CPM + */ +enum { + /* commands */ + InitRxTx = 0, + InitRx = 1, + InitTx = 2, + EnterHunt= 3, + StopTx= 4, + GracefulStopTx = 5, + InitIDMA = 5, + RestartTx = 6, + CloseRxBD = 7, + SetGroupAddr = 8, + SetTimer = 8, + GCITimeout = 9, + GCIAbort = 10, + StopIDMA = 11, + StartDSP = 12, + ArmIDMA = 13, + InitDSP = 13, + USBCmd = 15, + + /* channel IDs */ + SCC1ID= 0, + USBID= 0, + I2CID= 1, + IDMA1ID= 1, + SCC2ID= 4, + SPIID= 5, + IDMA2ID= 5, + TIMERID= 5, + SCC3ID= 8, + SMC1ID= 9, + DSP1ID=9, + SCC4ID= 12, + SMC2ID= 13, + DSP2ID= 13, + + BaudEnable = 1<<16, + + /* sicr */ + CLK1 = 4, /* SCC1,2 */ + CLK2 = 5, + CLK3 = 6, + CLK4 = 7, + CLK5 = CLK1, /* SCC3,4 */ + CLK6 = CLK2, + CLK7 = CLK3, + CLK8 = CLK4, +}; + +void cpmop(int, int, int); +#define ioplock() (m->iomem) +#define iopunlock() + +/* + * the structures below follow hardware/firmware layouts in the 8xx manuals: + * mind the data types, offsets and alignment + */ + +/* + * basic IO controller parameters (SMC and SCC) + */ +typedef struct IOCparam IOCparam; +struct IOCparam { + ushort rbase; + ushort tbase; + uchar rfcr; + uchar tfcr; + ushort mrblr; + ulong rstate; + ulong rptr; + ushort rbptr; + ushort rcnt; + ulong rtmp; + ulong tstate; + ulong tptr; + ushort tbptr; + ushort tcnt; + ulong ttmp; +}; + +typedef struct SCCparam SCCparam; +struct SCCparam { + IOCparam; + ulong rcrc; + ulong tcrc; +}; + +typedef struct SCC SCC; +struct SCC { + ulong gsmrl; + ulong gsmrh; + ushort psmr; + uchar rsvscc0[2]; + ushort todr; + ushort dsr; + ushort scce; + uchar rsvscc1[2]; + ushort sccm; + uchar rsvscc3; + uchar sccs; + ushort irmode; + ushort irsip; +}; + +typedef struct SMC SMC; +struct SMC { + uchar pad1[2]; + ushort smcmr; + uchar pad2[2]; + uchar smce; + uchar pad3[3]; + uchar smcm; + uchar pad4[5]; +}; + +typedef struct SPI SPI; +struct SPI { + ushort spmode; + uchar res1[4]; + uchar spie; + uchar res2[3]; + uchar spim; + uchar res3[2]; + uchar spcom; + uchar res4[10]; +}; + +typedef struct USB USB; +struct USB { /* 823 only */ + uchar usmod; + uchar usadr; + uchar uscom; + uchar rsvu1; + ushort usep[4]; + uchar rsvu2[4]; + ushort usber; + uchar rsvu3[2]; + ushort usbmr; + uchar rsvu4; + uchar usbs; + uchar rsvu5[8]; +}; + +typedef struct IMM IMM; +struct IMM { + struct { /* general SIU */ + ulong siumcr; + ulong sypcr; + uchar rsv0[0xE-0x8]; + ushort swsr; + ulong sipend; + ulong simask; + ulong siel; + uchar sivec; + uchar padv[3]; + ulong tesr; + uchar rsv1[0x30-0x24]; + ulong sdcr; + uchar rsv2[0x80-0x34]; + }; + struct { /* PCMCIA */ + struct { + ulong base; + ulong option; + } pcmr[8]; + uchar rsv3[0xe0-0xc0]; + ulong pgcra; + ulong pgcrb; + ulong pscr; + uchar rsv4[0xf0-0xec]; + ulong pipr; + uchar rsv5[4]; + ulong per; + uchar rsv6[4]; + }; + struct { /* MEMC */ + struct { + ulong base; + ulong option; + } memc[8]; + uchar rsv7a[0x24]; + ulong mar; + ulong mcr; + uchar rsv7b[4]; + ulong mamr; + ulong mbmr; + ushort mstat; + ushort mptpr; + ulong mdr; + uchar rsv7c[0x80]; + }; + struct { /* system integration timers */ + ushort tbscr; + uchar rsv8a[2]; + ulong tbrefu; + ulong tbrefl; + uchar rsv8b[0x14]; + ushort rtcsc; + uchar rsv8c[2]; + ulong rtc; + ulong rtsec; + ulong rtcal; + uchar rsv8d[0x10]; + ushort piscr; + ushort rsv8e; + ulong pitc; + ulong pitr; + uchar rsv8f[0x34]; + }; + struct { /* 280: clocks and resets */ + ulong sccr; + ulong plprcr; + ulong rsr; + uchar rsv9[0x300-0x28c]; + }; + struct { /* 300: system integration timers keys */ + ulong tbscrk; + ulong tbrefuk; + ulong tbreflk; + ulong tbk; + uchar rsv10a[0x10]; + ulong rtcsck; + ulong rtck; + ulong rtseck; + ulong rtcalk; + uchar rsv10b[0x10]; + ulong piscrk; + ulong pitck; + uchar rsv10c[0x38]; + }; + struct { /* 380: clocks and resets keys */ + ulong sccrk; + ulong plprcrk; + ulong rsrk; + uchar rsv11[0x800-0x38C]; + }; + struct { /* 800: video controller */ + ushort vccr; + ushort pad11a; + uchar vsr; + uchar pad11b; + uchar vcmr; + uchar pad11c; + ulong vbcb; + ulong pad11d; + ulong vfcr0; + ulong vfaa0; + ulong vfba0; + ulong vfcr1; + ulong vfaa1; + ulong vfba1; + uchar rsv11a[0x840-0x828]; + }; + struct { /* 840: LCD */ + ulong lccr; + ulong lchcr; + ulong lcvcr; + ulong rsv11b; + ulong lcfaa; + ulong lcfba; + uchar lcsr; + uchar rsv11c[0x860-0x859]; + }; + struct { /* 860: I2C */ + uchar i2mod; + uchar rsv12a[3]; + uchar i2add; + uchar rsv12b[3]; + uchar i2brg; + uchar rsv12c[3]; + uchar i2com; + uchar rsv12d[3]; + uchar i2cer; + uchar rsv12e[3]; + uchar i2cmr; + uchar rsv12[0x900-0x875]; + }; + struct { /* 900: DMA */ + uchar rsv13[4]; + ulong sdar; + uchar sdsr; + uchar pad1[3]; + uchar sdmr; + uchar pad2[3]; + uchar idsr1; + uchar pad3[3]; + uchar idmr1; + uchar pad4[3]; + uchar idsr2; + uchar pad5[3]; + uchar idmr2; + uchar pad6[0x930-0x91D]; + }; + struct { /* CPM interrupt control */ + ushort civr; + uchar pad7[0x940-0x932]; + ulong cicr; + ulong cipr; + ulong cimr; + ulong cisr; + }; + struct { /* input/output port */ + ushort padir; + ushort papar; + ushort paodr; + ushort padat; + uchar pad8[8]; + ushort pcdir; + ushort pcpar; + ushort pcso; + ushort pcdat; + ushort pcint; + uchar pad9[6]; + ushort pddir; + ushort pdpar; + ushort rsv14a; + ushort pddat; + uchar rsv14[0x980-0x978]; + }; + struct { /* CPM timers */ + ushort tgcr; + uchar rsv15a[0x990-0x982]; + ushort tmr1; + ushort tmr2; + ushort trr1; + ushort trr2; + ushort tcr1; + ushort tcr2; + ushort tcn1; + ushort tcn2; + ushort tmr3; + ushort tmr4; + ushort trr3; + ushort trr4; + ushort tcr3; + ushort tcr4; + ushort tcn3; + ushort tcn4; + ushort ter1; + ushort ter2; + ushort ter3; + ushort ter4; + uchar rsv15[0x9C0-0x9B8]; + }; + struct { /* CPM */ + ushort cpcr; + uchar res0[2]; + ushort rccr; + uchar res1; + uchar rmds; + uchar res2a[4]; + ushort rctr1; + ushort rctr2; + ushort rctr3; + ushort rctr4; + uchar res2[2]; + ushort rter; + uchar res3[2]; + ushort rtmr; + uchar rsv16[0x9F0-0x9DC]; + }; + union { /* BRG */ + struct { + ulong brgc1; + ulong brgc2; + ulong brgc3; + ulong brgc4; + }; + ulong brgc[4]; + }; + uchar skip0[0xAB2-0xA00]; /* USB, SCC, SMC, SPI: address using cpmdev(CP...)->regs */ + struct { /* PIP */ + ushort pipc; /* not 823 */ + ushort ptpr; /* not 823 */ + ulong pbdir; + ulong pbpar; + uchar pad10[2]; + ushort pbodr; + ulong pbdat; + uchar pad11[0xAE0-0xAC8]; + }; + struct { /* SI */ + ulong simode; + uchar sigmr; + uchar pad12; + uchar sistr; + uchar sicmr; + uchar pad13[4]; + ulong sicr; + ulong sirp; + uchar pad14[0xB00-0xAF4]; + }; + ulong vcram[64]; + ushort siram[256]; + ushort lcdmap[256]; +}; diff --git a/os/boot/rpcg/ip.h b/os/boot/rpcg/ip.h new file mode 100644 index 00000000..a39b5b4b --- /dev/null +++ b/os/boot/rpcg/ip.h @@ -0,0 +1,98 @@ +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 = 5000, /* milliseconds */ + 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 snce 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]; +}; diff --git a/os/boot/rpcg/l.s b/os/boot/rpcg/l.s new file mode 100644 index 00000000..a1022ff3 --- /dev/null +++ b/os/boot/rpcg/l.s @@ -0,0 +1,388 @@ +#include "mem.h" + +/* special instruction definitions */ +#define BDNE BC 0,2, +#define BDNZ BC 16,0, +#define NOOP OR R0,R0,R0 + +/* + * common ppc special purpose registers + */ +#define DSISR 18 +#define DAR 19 /* Data Address Register */ +#define DEC 22 /* Decrementer */ +#define SRR0 26 /* Saved Registers (exception) */ +#define SRR1 27 +#define SPRG0 272 /* Supervisor Private Registers */ +#define SPRG1 273 +#define SPRG2 274 +#define SPRG3 275 +#define TBRU 269 /* Time base Upper/Lower (Reading) */ +#define TBRL 268 +#define TBWU 285 /* Time base Upper/Lower (Writing) */ +#define TBWL 284 +#define PVR 287 /* Processor Version */ + +/* + * mpc82x-specific special purpose registers of interest here + */ +#define EIE 80 +#define EID 81 +#define NRI 82 +#define IMMR 638 +#define IC_CST 560 +#define IC_ADR 561 +#define IC_DAT 562 +#define DC_CST 568 +#define DC_ADR 569 +#define DC_DAT 570 +#define MI_CTR 784 +#define MI_AP 786 +#define MI_EPN 787 +#define MI_TWC 789 +#define MI_RPN 790 +#define MI_DBCAM 816 +#define MI_DBRAM0 817 +#define MI_DBRAM1 818 +#define MD_CTR 792 +#define M_CASID 793 +#define MD_AP 794 +#define MD_EPN 795 +#define M_TWB 796 +#define MD_TWC 797 +#define MD_RPN 798 +#define M_TW 799 +#define MD_DBCAM 824 +#define MD_DBRAM0 825 +#define MD_DBRAM1 826 + +/* as on 603e, apparently mtmsr needs help in some chip revisions */ +#define WAITMSR SYNC; ISYNC + +/* use of SPRG registers in save/restore */ +#define SAVER0 SPRG0 +#define SAVER1 SPRG1 +#define SAVELR SPRG2 +#define SAVECR SPRG3 + +#define UREGSIZE ((8+32)*4) +#define UREGSPACE (UREGSIZE+8) /* allow for arg to trap, and align */ + +/* + * This code is loaded by the ROM loader at location 0x3000, + * or lives in flash memory at FLASHMEM+0x100 + * Move it to high memory so that it can load the kernel at 0x0000. + */ + +#define LOADCODEBASE 0x3000 /* when downloaded in S records */ +#define FLASHCODEBASE (FLASHMEM+0x20000+0x100) /* when in flash */ + + TEXT start(SB), $-4 + MOVW MSR, R3 + MOVW $(EE|IP|RI), R4 + ANDN R4, R3 + OR $ME, R3 + SYNC + MOVW R3, MSR /* turn off interrupts but enable traps */ + WAITMSR + +/* + * reset the caches and disable them for now + */ + MOVW SPR(IC_CST), R4 /* read and clear */ + MOVW $(5<<25), R4 + MOVW R4, SPR(IC_CST) /* unlock all */ + ISYNC + MOVW $(6<<25), R4 + MOVW R4, SPR(IC_CST) /* invalidate all */ + ISYNC + MOVW $(2<<25), R4 + MOVW R4, SPR(IC_CST) /* disable i-cache */ + ISYNC + + SYNC + MOVW SPR(DC_CST), R4 /* read and clear */ + MOVW $(10<<24), R4 + MOVW R4, SPR(DC_CST) /* unlock all */ + ISYNC + MOVW $(12<<24), R4 + MOVW R4, SPR(DC_CST) /* invalidate all */ + ISYNC + MOVW $(4<<24), R4 + MOVW R4, SPR(DC_CST) /* disable i-cache */ + ISYNC + + MOVW $7, R4 + MOVW R4, SPR(158) /* cancel `show cycle' for normal instruction execution */ + +/* + * set other system configuration values + */ + MOVW SPR(IMMR), R5 /* save initial space pointer */ + MOVW $INTMEM, R4 + MOVW R4, SPR(IMMR) /* set internal memory base */ + MOVW $0xFFFFFF88, R3 + MOVW R3, 4(R4) /* disable watchdog in sypcr */ + MOVW $0x01012440, R3 + MOVW R3, 0(R4) /* siumcr */ + +/* + * system initialisation (init and map DRAM) + */ + MOVW $0, R0 + MOVW $setSB(SB), R2 +#ifndef confrpcg + MOVW $(0xF000<<16), R3 +/*MOVW R0, R3*/ + ANDCC R5, R3 /* initial space is high? */ + BEQ notrom + MOVW $FLASHCODEBASE, R5 /* where $start(SB) actually is now */ + MOVW $start(SB), R4 /* logical start address */ + SUB R4, R5, R6 /* text relocation value */ + MOVW $etext(SB), R7 + SUB R4, R7 + ADD R5, R7 /* data address in ROM */ + MOVW $bdata(SB), R8 + SUB R8, R2 + ADD R7, R2 /* relocate SB: SB' = romdata+(SB-bdata) */ + MOVW $sysinit0(SB), R4 + ADD R6, R4 /* relocate sysinit0's address */ + MOVW R4, CTR + MOVW $inmem(SB), R4 + ADD R6, R4 + MOVW R4, LR /* and the return address */ + BR (CTR) /* call sysinit0 */ + TEXT inmem(SB), $-4 + MOVW $FLASHCODEBASE, R3 + BR cpu0 +notrom: + MOVW $start(SB), R6 + SUB R6, R2 + ADD $LOADCODEBASE, R2 + BL sysinit0(SB) + MOVW $LOADCODEBASE, R3 +#endif + +/* + * cpu 0 + * relocate bootstrap to our link addresses for text and data + * set new PC + */ +cpu0: + MOVW $setSB(SB), R2 /* set correct static base register */ +#ifndef confrpcg + MOVW $start(SB), R4 + MOVW $etext(SB), R5 + SUB R4, R5 + CMP R4, R3 /* already there? */ + BNE copytext + ADD R5, R3 /* start of data image */ +#else + MOVW $etext(SB), R3 +#endif + BR copydata + +copytext: + ADD $3, R5 + SRAW $2, R5 + MOVW R5, CTR + SUB $4, R4 + SUB $4, R3 +copyt: /* copy text */ + MOVWU 4(R3), R5 + MOVWU R5, 4(R4) + BDNZ copyt + ADD $4, R3 + +copydata: + /* copy data */ + MOVW $bdata(SB), R4 + CMP R4, R3 /* already there? */ + BEQ loadkpc + MOVW $edata(SB), R5 + SUB R4, R5 + ADD $3, R5 + SRAW $2, R5 + MOVW R5, CTR + SUB $4, R4 + SUB $4, R3 +copyd: + MOVWU 4(R3), R5 + MOVWU R5, 4(R4) + BDNZ copyd +#endif + + /* load correct PC */ +loadkpc: + MOVW $start1(SB), R3 + MOVW R3, LR + BR (LR) +TEXT start1(SB), $-4 + MOVW $edata(SB), R3 + MOVW $end(SB), R4 + SUBCC R3, R4 + BLE skipz + SRAW $2, R4 + MOVW R4, CTR + SUB $4, R3 + MOVW $0, R0 +zero: + MOVWU R0, 4(R3) + BDNZ zero +skipz: + MOVW $mach0(SB), R1 + MOVW R1, m(SB) + ADD $(MACHSIZE-8), R1 + MOVW $0, R0 + + BL sysinit0(SB) + + BL main(SB) + BR 0(PC) + +TEXT ledx(SB), $0 + + MOVW $BCSRMEM, R8 + MOVW 0(R8), R3 + MOVW $(0x0800<<16), R5 + ANDN R5, R3, R3 + MOVW R3, 0(R8) + BR 0(PC) + +TEXT getmsr(SB), $0 + MOVW MSR, R3 + RETURN + +TEXT putmsr(SB), $0 + SYNC + MOVW R3, MSR + WAITMSR + RETURN + +TEXT eieio(SB), $0 + EIEIO + RETURN + +TEXT idle(SB), $0 + RETURN + +TEXT spllo(SB), $0 + MOVW MSR, R3 + OR $EE, R3, R4 + SYNC + MOVW R4, MSR + WAITMSR + RETURN + +TEXT splhi(SB), $0 + MOVW MSR, R3 + RLWNM $0, R3, $~EE, R4 + SYNC + MOVW R4, MSR + WAITMSR + RETURN + +TEXT splx(SB), $0 + MOVW MSR, R4 + RLWMI $0, R3, $EE, R4 + SYNC + MOVW R4, MSR + WAITMSR + RETURN + +TEXT gettbl(SB), $0 +/* MOVW SPR(TBRL), R3 */ + WORD $0x7c6c42e6 /* mftbl on 8xx series */ + RETURN + +TEXT getpvr(SB), $0 + MOVW SPR(PVR), R3 + RETURN + +TEXT getimmr(SB), $0 + MOVW SPR(IMMR), R3 + RETURN + +TEXT getdec(SB), $0 + MOVW SPR(DEC), R3 + RETURN + +TEXT putdec(SB), $0 + MOVW R3, SPR(DEC) + RETURN + +/* + * save state in Ureg on kernel stack. + * enter with R0 giving the PC from the call to `exception' from the vector. + * on return, SB (R2) has been set, and R3 has the Ureg* + */ +TEXT saveureg(SB), $-4 + SUB $UREGSPACE, R1 + MOVMW R2, 48(R1) /* r2: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 SPR(SAVECR), R5 /* CR */ + MOVW R5, 28(R1) + MOVW SPR(SAVELR), R6 /* LR */ + MOVW R6, 24(R1) + /* pad at 20(R1) */ + MOVW SPR(SRR0), R4 + MOVW R4, 16(R1) /* old PC */ + MOVW SPR(SRR1), R5 + MOVW R5, 12(R1) + MOVW R0, 8(R1) /* cause/vector, encoded in LR from vector */ + ADD $8, R1, R3 /* Ureg* */ + STWCCC R3, (R1) /* break any pending reservations */ + MOVW $0, R0 /* R0ISZERO */ + BR (LR) + +/* + * restore state from Ureg + * SB (R2) is unusable on return + */ +TEXT restoreureg(SB), $-4 + MOVMW 48(R1), R2 /* r2:r31 */ + /* defer R1 */ + MOVW 40(R1), R0 + MOVW R0, SPR(SAVER0) + 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, SPR(SAVELR) /* LR */ + /* pad, skip */ + MOVW 16(R1), R0 + MOVW R0, SPR(SRR0) /* old PC */ + MOVW 12(R1), R0 + MOVW R0, SPR(SRR1) /* old MSR */ + /* cause, skip */ + MOVW 44(R1), R1 /* old SP */ + BR (LR) + +TEXT exception(SB), $-4 + MOVW R1, SPR(SAVER1) + MOVW CR, R0 + MOVW R0, SPR(SAVECR) + MOVW LR, R0 + BL saveureg(SB) + MOVW $0, R0 + BL trap(SB) + BL restoreureg(SB) + MOVW SPR(SAVELR), R0 + MOVW R0, LR + MOVW SPR(SAVER0), R0 + ISYNC + RFI + +GLOBL mach0+0(SB), $MACHSIZE +GLOBL m(SB), $4 diff --git a/os/boot/rpcg/lib.h b/os/boot/rpcg/lib.h new file mode 100644 index 00000000..1eb0532d --- /dev/null +++ b/os/boot/rpcg/lib.h @@ -0,0 +1,106 @@ +/* + * functions (possibly) linked in, complete, from libc. + */ + +/* + * mem routines + */ +extern void* memccpy(void*, void*, int, long); +extern void* memset(void*, int, long); +extern int memcmp(void*, void*, long); +extern void* memmove(void*, void*, long); +extern void* memchr(void*, int, long); + +/* + * string routines + */ +extern char* strcat(char*, char*); +extern char* strchr(char*, char); +extern int strcmp(char*, char*); +extern char* strcpy(char*, char*); +extern char* strncat(char*, char*, long); +extern char* strncpy(char*, char*, long); +extern int strncmp(char*, char*, long); +extern long strlen(char*); +extern char* strrchr(char*, char); +extern char* strstr(char*, char*); + +/* + * print routines + * Fconv isn't used but is defined to satisfy prototypes in libg.h + * that are never called. + */ +typedef struct Fconv Fconv; + +extern char* donprint(char*, char*, char*, void*); +extern int sprint(char*, char*, ...); +extern int print(char*, ...); + +#define PRINTSIZE 256 + +/* + * one-of-a-kind + */ +extern int atoi(char*); +extern long strtol(char*, char**, int); +extern ulong strtoul(char*, char**, int); +extern long end; + +/* + * Syscall data structures + */ + +#define MORDER 0x0003 /* mask for bits defining order of mounting */ +#define MREPL 0x0000 /* mount replaces object */ +#define MBEFORE 0x0001 /* mount goes before others in union directory */ +#define MAFTER 0x0002 /* mount goes after others in union directory */ +#define MCREATE 0x0004 /* permit creation in mounted directory */ +#define MMASK 0x0007 /* all bits on */ + +#define OREAD 0 /* open for read */ +#define OWRITE 1 /* write */ +#define ORDWR 2 /* read and write */ +#define OEXEC 3 /* execute, == read but check execute permission */ +#define OTRUNC 16 /* or'ed in (except for exec), truncate file first */ +#define OCEXEC 32 /* or'ed in, close on exec */ +#define ORCLOSE 64 /* or'ed in, remove on close */ + +#define NCONT 0 /* continue after note */ +#define NDFLT 1 /* terminate after note */ + +typedef struct Qid Qid; +typedef struct Dir Dir; +typedef struct Waitmsg Waitmsg; + +#define ERRLEN 64 +#define DIRLEN 116 +#define NAMELEN 28 + +struct Qid +{ + ulong path; + ulong vers; +}; + +struct Dir +{ + char name[NAMELEN]; + char uid[NAMELEN]; + char gid[NAMELEN]; + Qid qid; + ulong mode; + long atime; + long mtime; + vlong length; + short type; + short dev; +}; + +struct Waitmsg +{ + int pid; /* of loved one */ + int status; /* unused; a placeholder */ + ulong time[3]; /* of loved one */ + char msg[ERRLEN]; +}; +#define nelem(x) (sizeof(x)/sizeof((x)[0])) diff --git a/os/boot/rpcg/libg.h b/os/boot/rpcg/libg.h new file mode 100644 index 00000000..5c2cec26 --- /dev/null +++ b/os/boot/rpcg/libg.h @@ -0,0 +1,418 @@ +#pragma src "/sys/src/libg" +#pragma lib "libg.a" + +enum /* constants for I/O to devgraphics */ +{ + Tilehdr = 40, + Tilesize = 8000 +}; + +/* + * you may think it's a blit, but it's gnot + */ +enum +{ + EMAXMSG = 128+8192, /* size of 9p header+data */ +}; + +/* + * Types + */ + +typedef struct Bitmap Bitmap; +typedef struct Display Display; +typedef struct Point Point; +typedef struct Rectangle Rectangle; +typedef struct Cursor Cursor; +typedef struct Mouse Mouse; +typedef struct Menu Menu; +typedef struct Font Font; +typedef struct Fontchar Fontchar; +typedef struct Subfont Subfont; +typedef struct Cachefont Cachefont; +typedef struct Cacheinfo Cacheinfo; +typedef struct Cachesubf Cachesubf; +typedef struct Event Event; +typedef struct Slave Slave; +typedef struct Ebuf Ebuf; +typedef struct RGB RGB; +typedef struct Linedesc Linedesc; +typedef struct DRefret DRefret; + +struct DRefret +{ + int n; /* number of bytes */ + int dy; /* number of lines */ + uchar *dp; /* pointer to data */ +}; + +struct Point +{ + int x; + int y; +}; + +struct Rectangle +{ + Point min; + Point max; +}; + +typedef DRefret DRefresh(Display*, int, Rectangle, uchar*, uchar*, int); + +struct Bitmap +{ + Rectangle r; /* rectangle in data area, local coords */ + Rectangle clipr; /* clipping region */ + int ldepth; /* log base 2 of number of bits per pixel */ + ulong *base; /* pointer to start of data */ + int zero; /* base+zero=&word containing (0,0) */ + ulong width; /* width in words of total data area */ + Display *display; /* if present */ +}; + +struct Display +{ + uchar *data; /* transfer buffer */ + Rectangle r; + int ldepth; + Rectangle bb; /* bounding box of changes */ + int waste; /* unused part of bb */ + Rectangle bound; /* memory for boundin/boundout */ + Bitmap *image; /* owner */ + int id; + int fd; + int ctlfd; + int local; + int bytewidth; + void *drdata1; /* storage for drefresh() */ + void *drdata2; /* storage for drefresh() */ + DRefresh *drefresh; +}; + + +struct Mouse +{ + int buttons; /* bit array: LMR=124 */ + Point xy; + ulong msec; +}; + +struct Cursor +{ + Point offset; + uchar clr[2*16]; + uchar set[2*16]; +}; + +struct Menu +{ + char **item; + char *(*gen)(int); + int lasthit; +}; + +struct Linedesc +{ + int x0; + int y0; + char xmajor; + char slopeneg; + long dminor; + long dmajor; +}; + +/* + * Subfonts + * + * given char c, Subfont *f, Fontchar *i, and Point p, one says + * i = f->info+c; + * bitblt(b, Pt(p.x+i->left,p.y+i->top), + * bitmap, Rect(i->x,i->top,(i+1)->x,i->bottom), + * fc); + * p.x += i->width; + * where bitmap b is the repository of the images. + * + */ + +struct Fontchar +{ + short x; /* left edge of bits */ + uchar top; /* first non-zero scan-line */ + uchar bottom; /* last non-zero scan-line + 1 */ + char left; /* offset of baseline */ + uchar width; /* width of baseline */ +}; + +struct Subfont +{ + short n; /* number of chars in font */ + uchar height; /* height of bitmap */ + char ascent; /* top of bitmap to baseline */ + Fontchar *info; /* n+1 character descriptors */ + Bitmap *bits; /* of font */ +}; + +enum +{ + /* starting values */ + LOG2NFCACHE = 6, + NFCACHE = (1<<LOG2NFCACHE), /* #chars cached */ + NFLOOK = 5, /* #chars to scan in cache */ + NFSUBF = 2, /* #subfonts to cache */ + /* max value */ + MAXFCACHE = 2048+NFLOOK, /* generous upper limit */ + MAXSUBF = 50, /* generous upper limit */ + /* deltas */ + DSUBF = 4, + /* expiry ages */ + SUBFAGE = 10000, + CACHEAGE = 10000, +}; + +struct Cachefont +{ + Rune min; /* lowest rune value to be taken from subfont */ + Rune max; /* highest rune value+1 to be taken from subfont */ + int offset; /* position in subfont of character at min */ + int abs; /* name has been made absolute */ + char *name; +}; + +struct Cacheinfo +{ + Rune value; /* value of character at this slot in cache */ + ushort age; + ulong xright; /* right edge of bits */ + Fontchar; +}; + +struct Cachesubf +{ + ulong age; /* for replacement */ + Cachefont *cf; /* font info that owns us */ + Subfont *f; /* attached subfont */ +}; + +struct Font +{ + char *name; + short height; /* max height of bitmap, interline spacing */ + short ascent; /* top of bitmap to baseline */ + int maxldepth; /* over all loaded subfonts */ + short width; /* widest so far; used in caching only */ + short ldepth; /* of images */ + short nsub; /* number of subfonts */ + ulong age; /* increasing counter; used for LRU */ + int ncache; /* size of cache */ + int nsubf; /* size of subfont list */ + Cacheinfo *cache; + Cachesubf *subf; + Cachefont **sub; /* as read from file */ + Bitmap *cacheimage; +}; + +struct Event +{ + int kbdc; + Mouse mouse; + int n; /* number of characters in mesage */ + uchar data[EMAXMSG]; /* message from an arbitrary file descriptor */ +}; + +struct Slave{ + int pid; + Ebuf *head; /* queue of messages for this descriptor */ + Ebuf *tail; +}; + +struct Ebuf{ + Ebuf *next; + int n; /* number of bytes in buf */ + uchar buf[EMAXMSG]; +}; + +struct RGB +{ + ulong red; + ulong green; + ulong blue; +}; + +/* + * Codes for bitblt etc. + * + * D + * 0 1 + * --------- + * 0 | 1 | 2 | + * S |---|---| + * 1 | 4 | 8 | + * --------- + * + * Usually used as D|S; DorS is so tracebacks are readable. + */ +typedef +enum Fcode +{ + Zero = 0x0, + DnorS = 0x1, + DandnotS = 0x2, + notS = 0x3, + notDandS = 0x4, + notD = 0x5, + DxorS = 0x6, + DnandS = 0x7, + DandS = 0x8, + DxnorS = 0x9, + D = 0xA, + DornotS = 0xB, + S = 0xC, + notDorS = 0xD, + DorS = 0xE, + F = 0xF, +} Fcode; + +/* + * Miscellany + */ + +extern Point add(Point, Point), sub(Point, Point); +extern Point mul(Point, int), div(Point, int); +extern Rectangle rsubp(Rectangle, Point), raddp(Rectangle, Point), inset(Rectangle, int); +extern Rectangle rmul(Rectangle, int), rdiv(Rectangle, int); +extern Rectangle rshift(Rectangle, int), rcanon(Rectangle); +extern Bitmap* balloc(Rectangle, int); +extern Bitmap* ballocnomem(Rectangle, int); +extern Bitmap* brealloc(Bitmap*, Rectangle, int); +extern Bitmap* breallocnomem(Bitmap*, Rectangle, int); +extern int bbytewidth(Bitmap*, int*, int*); +extern void bfree(Bitmap*); +extern void bfreemem(Bitmap*); +extern int rectclip(Rectangle*, Rectangle); +extern void binit(void(*)(char*), char*, char*); +extern void binit1(void(*)(char*), char*, char*, int); +extern void bclose(void); +extern void berror(char*); +extern void bitblt(Bitmap*, Point, Bitmap*, Rectangle, Fcode); +extern int bitbltclip(void*); +extern Font* rdfontfile(char*, int); +extern void ffree(Font*); +extern void fminldepth(Font*); +extern Font* mkfont(Subfont*, Rune); +extern Subfont* subfalloc(int, int, int, Fontchar*, Bitmap*); +extern void subffree(Subfont*); +extern int cachechars(Font*, char**, ushort*, int, int*); +extern Point string(Bitmap*, Point, Font*, char*, Fcode); +extern Point subfstring(Bitmap*, Point, Subfont*, char*, Fcode); +extern void segment(Bitmap*, Point, Point, int, Fcode); +extern void point(Bitmap*, Point, int, Fcode); +extern void arc(Bitmap*, Point, Point, Point, int, Fcode); +extern void circle(Bitmap*, Point, int, int, Fcode); +extern void disc(Bitmap*, Point, int, int, Fcode); +extern void ellipse(Bitmap*, Point, int, int, int, Fcode); +extern long strwidth(Font*, char*); +extern void agefont(Font*); +extern int loadchar(Font*, Rune, Cacheinfo*, int, int); +extern Point strsize(Font*, char*); +extern long charwidth(Font*, Rune); +extern void texture(Bitmap*, Rectangle, Bitmap*, Fcode); +extern void wrbitmap(Bitmap*, int, int, uchar*); +extern void rdbitmap(Bitmap*, int, int, uchar*); +extern void wrbitmapfile(int, Bitmap*); +extern Bitmap* rdbitmapfile(int); +extern void wrsubfontfile(int, Subfont*); +extern void wrcolmap(Bitmap*, RGB*); +extern void rdcolmap(Bitmap*, RGB*); +extern Subfont* rdsubfontfile(int, Bitmap*); +extern void _unpackinfo(Fontchar*, uchar*, int); + +extern int ptinrect(Point, Rectangle), rectinrect(Rectangle, Rectangle); +extern int rectXrect(Rectangle, Rectangle); +extern int eqpt(Point, Point), eqrect(Rectangle, Rectangle); +extern void border(Bitmap*, Rectangle, int, Fcode); +extern void cursorswitch(Cursor*); +extern void cursorset(Point); +extern Rectangle bscreenrect(Rectangle*); +extern void bflush(void); +extern void bexit(void); +extern int _clipline(Rectangle, Point*, Point*, Linedesc*); +extern int clipline(Rectangle, Point*, Point*); +extern int clipr(Bitmap*, Rectangle); + +extern void einit(ulong); +extern ulong estart(ulong, int, int); +extern ulong etimer(ulong, int); +extern ulong event(Event*); +extern ulong eread(ulong, Event*); +extern Ebuf* ebread(Slave*); +extern Mouse emouse(void); +extern int ekbd(void); +extern int ecanread(ulong); +extern int ecanmouse(void); +extern int ecankbd(void); +extern void ereshaped(Rectangle); /* supplied by user */ +extern int menuhit(int, Mouse*, Menu*); +extern Rectangle getrect(int, Mouse*); +extern ulong rgbpix(Bitmap*, RGB); +extern int _gminor(long, Linedesc*); + +enum{ + Emouse = 1, + Ekeyboard = 2, +}; + +enum +{ + MAXSLAVE = 32, +}; + +#define Pt(x, y) ((Point){(x), (y)}) +#define Rect(x1, y1, x2, y2) ((Rectangle){Pt(x1, y1), Pt(x2, y2)}) +#define Rpt(p1, p2) ((Rectangle){(p1), (p2)}) + + +#define Dx(r) ((r).max.x-(r).min.x) +#define Dy(r) ((r).max.y-(r).min.y) + +extern Bitmap screen; +extern Font *font; +extern uchar _btmp[8192]; + +extern int _mousefd; +extern int _cursorfd; + +#define BGSHORT(p) (((p)[0]<<0) | ((p)[1]<<8)) +#define BGLONG(p) ((BGSHORT(p)<<0) | (BGSHORT(p+2)<<16)) +#define BPSHORT(p, v) ((p)[0]=(v), (p)[1]=((v)>>8)) +#define BPLONG(p, v) (BPSHORT(p, (v)), BPSHORT(p+2, (v)>>16)) + +ulong *wordaddr(Bitmap*, Point); +uchar *byteaddr(Bitmap*, Point); +int dfree(Display*); +int dwritectl(Display*, char*, int); +int dreadctl(Display*, char*, int); +int dinfo(Display*, int, int*, Rectangle*); +void* dinit(Display*, Bitmap*, int, int); +int ddelete(Display*); +void dfreemem(Display*); +int dreadctl(Display*, char*, int); +int dwritectl(Display*, char*, int); +void dbound(Display*, Rectangle); +void bload(Bitmap*, Rectangle, uchar*); +ulong bunload(Bitmap*, Rectangle, uchar*); +void drefresh(Display*, Rectangle); +Display *dopen(char*, int, DRefresh*); +Bitmap* dbitmap(Display*, DRefresh*, int); +void dclose(Display*); +void dflush(Display*); +void _bltinit(void); +Bitmap* battach(Bitmap*, int, int); +int readmouse(Mouse*); +int atomouse(Mouse*, char*, int); + +/* + * Refresh functions + */ +DRefresh drtexture; +DRefresh drbackstore; diff --git a/os/boot/rpcg/main.c b/os/boot/rpcg/main.c new file mode 100644 index 00000000..10600eef --- /dev/null +++ b/os/boot/rpcg/main.c @@ -0,0 +1,527 @@ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" + +#include "dosfs.h" + +typedef struct Type Type; +typedef struct Medium Medium; +typedef struct Mode Mode; + +enum { + Dany = -1, + Nmedia = 16, + + /* DS1 switch options */ + Sflashfs = 1<<0, /* take local fs from flash */ + Snotflash = 1<<1, /* don't boot from flash */ +}; + +enum { /* type */ + Tflash, + Tuart, + Tether, + Thard, + + Tany = -1, +}; + +enum { /* flag and name */ + Fnone = 0x00, + + Fdos = 0x01, + Ndos = 0x00, + Fboot = 0x02, + Nboot = 0x01, + Fbootp = 0x04, + Nbootp = 0x02, + Fflash = 0x08, + Fuart = 0x10, + NName = 0x03, + + Fany = Fbootp|Fboot|Fdos|Fflash|Fuart, + + Fini = 0x10, + Fprobe = 0x80, +}; + +enum { /* mode */ + Mauto = 0x00, + Mlocal = 0x01, + Manual = 0x02, + NMode = 0x03, +}; + +typedef struct Type { + int type; + char *cname; + int flag; + int (*init)(void); + long (*read)(int, void*, long); + long (*seek)(int, long); + Partition* (*setpart)(int, char*); + char* name[NName]; + + int mask; + Medium* media; +} Type; + +typedef struct Medium { + Type* type; + int flag; + Partition* partition; + Dos; + + Medium* next; +} Medium; + +typedef struct Mode { + char* name; + int mode; +} Mode; + +static Type types[] = { + { Tflash, "flash", + Fflash, + flashinit, 0, 0, 0, + { 0, "F", 0, } + }, +/* + { Tuart, "uart", + Fuart|Fboot, + uartinit, uartread, uartseek, setuartpart, + { 0, "u", 0, } + }, +*/ + { Tether, "ether", + Fbootp, + etherinit, 0, 0, 0, + { 0, 0, "e", }, + }, + { Thard, "ata", + Fini|Fboot|Fdos, + 0, 0, 0, 0, /* not used now, will be later with PCMCIA */ + { "hd", "h", 0, }, + }, + {-1}, +}; + +static Medium media[Nmedia]; +static Medium *curmedium = media; + +static Mode modes[NMode+1] = { + [Mauto] { "auto", Mauto, }, + [Mlocal] { "local", Mlocal, }, + [Manual] { "manual", Manual, }, +}; + +static char *inis[] = { + "inferno/inferno.ini", + "inferno.ini", + "plan9/plan9.ini", + "plan9.ini", + 0, +}; +char **ini; +int predawn; + +static int +parse(char *line, int *type, int *flag, int *dev, char *file) +{ + Type *tp; + char buf[2*NAMELEN], *v[4], *p; + int i; + + strcpy(buf, line); + switch(getcfields(buf, v, 4, "!")){ + + case 3: + break; + + case 2: + v[2] = ""; + break; + + default: + return 0; + } + + *flag = 0; + for(tp = types; tp->cname; tp++){ + for(i = 0; i < NName; i++){ + + if(tp->name[i] == 0 || strcmp(v[0], tp->name[i])) + continue; + *type = tp->type; + *flag |= 1<<i; + + if((*dev = strtoul(v[1], &p, 0)) == 0 && p == v[1]) + return 0; + + strcpy(file, v[2]); + + return 1; + } + } + + return 0; + +} + +static int +boot(Medium *mp, int flag, char *file) +{ + Dosfile df; + char ixdos[128], *p; + int r; + + uartsetboot(0); + if(flag & Fbootp){ + sprint(BOOTLINE, "%s!%d", mp->type->name[Nbootp], mp->dev); + return bootp(mp->dev, file); + } + + if(flag & Fflash){ + if(mp->flag & Fflash && flashbootable(0)) + flashboot(mp->dev); + } + + if(flag & Fboot){ + + if(mp->flag & Fini){ + (*mp->type->setpart)(mp->dev, "disk"); + plan9ini(mp, nil); + } + if(file == 0 || *file == 0) + file = mp->partition->name; + (*mp->type->setpart)(mp->dev, file); + sprint(BOOTLINE, "%s!%d!%s", mp->type->name[Nboot], mp->dev, file); + r = plan9boot(mp->dev, mp->seek, mp->read); + uartsetboot(0); + return r; + } + + if(flag & Fdos){ + if(mp->type->setpart) + (*mp->type->setpart)(mp->dev, "disk"); + if(mp->flag & Fini) + plan9ini(mp, nil); + if(file == 0 || *file == 0){ + strcpy(ixdos, *ini); + if(p = strrchr(ixdos, '/')) + p++; + else + p = ixdos; + strcpy(p, "impc"); + if(dosstat(mp, ixdos, &df) <= 0) + return -1; + } + else + strcpy(ixdos, file); + sprint(BOOTLINE, "%s!%d!%s", mp->type->name[Ndos], mp->dev, ixdos); + return dosboot(mp, ixdos); + } + + return -1; +} + +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 dombr, i, start; + Medium *mp; + Dosfile df; + Partition *pp; + + for(tp = types; tp->cname; tp++){ + if(type != Tany && type != tp->type || tp->init == 0) + continue; + + 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<<i)) == 0) + continue; + tp->mask &= ~(1<<i); + + if((mp = allocm(tp)) == 0) + continue; + + mp->dev = i; + mp->flag = tp->flag; + mp->seek = tp->seek; + mp->read = tp->read; + mp->type = tp; + + if(mp->flag & Fboot){ + if((mp->partition = (*tp->setpart)(i, "boot")) == 0) + mp->flag &= ~Fboot; + if((mp->flag & (Fflash|Fuart)) == 0) + (*tp->setpart)(i, "disk"); + } + + if(mp->flag & Fdos){ + start = 0; + dombr = 1; + if(mp->type->setpart){ + if(pp = (*mp->type->setpart)(i, "dos")){ + if(start = pp->start) + dombr = 0; + } + (*tp->setpart)(i, "disk"); + } + if(dosinit(mp, start, dombr) < 0) + mp->flag &= ~(Fini|Fdos); + else + print("dos init failed\n"); + } + + if(mp->flag & Fini){ + mp->flag &= ~Fini; + for(ini = inis; *ini; ini++){ + if(dosstat(mp, *ini, &df) <= 0) + continue; + mp->flag |= Fini; + break; + } + } + + if((flag & mp->flag) && (dev == Dany || dev == i)) + return mp; + } + } + + return 0; +} + +void +main(void) +{ + Medium *mp; + int dev, flag, i, mode, tried, type, options; + char def[2*NAMELEN], file[2*NAMELEN], line[80], *p; + Type *tp; + + machinit(); + archinit(); + meminit(); + cpminit(); + trapinit(); + consinit(); /* screen and keyboard initially */ +/* screeninit(); */ + cpuidprint(); + alarminit(); + clockinit(); +print("predawn\n"); + predawn = 0; + spllo(); +print("dawn\n"); + options = archoptionsw(); +print("options=#%ux\n", options); + + mp = 0; + for(tp = types; tp->cname; tp++){ + if(tp->type == Tether) + continue; + if((mp = probe(tp->type, Fini, Dany)) && (mp->flag & Fini)){ + plan9ini(mp, nil); + break; + } + } + + if(mp == 0 || (mp->flag & Fini) == 0) + plan9ini(nil, flashconfig(0)); + + //consinit(); /* establish new console location */ + + if((options & Snotflash) == 0 && flashbootable(0)){ + print("Flash boot\n"); + flashboot(0); + } + + tried = 0; + mode = Mauto; + p = getconf("bootfile"); + flag = 0; + + 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(parse(p, &type, &flag, &dev, file) == 0) { + print("Bad bootfile syntax: %s\n", p); + goto done; + } + mp = probe(type, flag, dev); + if(mp == 0) { + print("Cannot access device: %s\n", p); + goto done; + } + tried = boot(mp, flag, file); + } +done: + if(tried == 0 && mode != Manual){ + flag = Fany; + if(mode == Mlocal) + flag &= ~Fbootp; + if(options & Snotflash) + flag &= ~Fflash; + if((mp = probe(Tany, flag, Dany)) != 0) + boot(mp, flag & mp->flag, 0); + } + + def[0] = 0; + probe(Tany, Fnone, Dany); + + flag = 0; + for(tp = types; tp->cname; tp++){ + for(mp = tp->media; mp; mp = mp->next){ + if(flag == 0){ + flag = 1; + print("Boot devices:"); + } + + if(mp->flag & Fbootp) + print(" %s!%d", mp->type->name[Nbootp], mp->dev); + if(mp->flag & Fdos) + print(" %s!%d", mp->type->name[Ndos], mp->dev); + if(mp->flag & (Fflash|Fuart) || mp->flag & Fboot) + print(" %s!%d", mp->type->name[Nboot], mp->dev); + } + } + if(flag) + print("\n"); + + for(;;){ + if(getstr("boot from", line, sizeof(line), def) >= 0){ + if(parse(line, &type, &flag, &dev, file)){ + if(mp = probe(type, flag, dev)) + boot(mp, flag, file); + } + } + def[0] = 0; + } +} + +void +machinit(void) +{ + memset(m, 0, sizeof(*m)); + m->delayloop = 20000; + m->cpupvr = getpvr(); + m->iomem = KADDR(INTMEM); +} + +int +getcfields(char* lp, char** fields, int n, char* sep) +{ + int i; + + for(i = 0; lp && *lp && i < n; i++){ + while(*lp && strchr(sep, *lp) != 0) + *lp++ = 0; + if(*lp == 0) + break; + fields[i] = lp; + while(*lp && strchr(sep, *lp) == 0){ + if(*lp == '\\' && *(lp+1) == '\n') + *lp++ = ' '; + lp++; + } + } + + return i; +} + +static Map memv[512]; +static RMap rammap = {"physical memory"}; + +void +meminit(void) +{ + ulong e; + + mapinit(&rammap, memv, sizeof(memv)); + e = PADDR(&end); + mapfree(&rammap, e, 4*1024*1024-e); /* fixed 4Mbytes is plenty for bootstrap */ +} + +void* +ialloc(ulong n, int align) +{ + ulong a; + int s; + + if(align <= 0) + align = 4; + s = splhi(); + a = mapalloc(&rammap, 0, n, align); + splx(s); + if(a == 0) + panic("ialloc"); + return memset(KADDR(a), 0, n); +} + +void* +malloc(ulong n) +{ + ulong *p; + + n = ((n+sizeof(int)-1)&~(sizeof(int)-1))+2*sizeof(int); + p = ialloc(n, sizeof(int)); + *p++ = 0xcafebeef; + *p++ = n; + return p; +} + +void +free(void *ap) +{ + int s; + ulong *p; + + p = ap; + if(p){ + if(*(p -= 2) != 0xcafebeef) + panic("free"); + s = splhi(); + mapfree(&rammap, (ulong)p, p[1]); + splx(s); + } +} + +void +sched(void) +{ +} diff --git a/os/boot/rpcg/mem.c b/os/boot/rpcg/mem.c new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/os/boot/rpcg/mem.c diff --git a/os/boot/rpcg/mem.h b/os/boot/rpcg/mem.h new file mode 100644 index 00000000..f31e5622 --- /dev/null +++ b/os/boot/rpcg/mem.h @@ -0,0 +1,94 @@ +/* + * Memory and machine-specific definitions. Used in C and assembler. + */ + +/* + * Sizes + */ +#define BI2BY 8 /* bits per byte */ +#define BI2WD 32 /* bits per word */ +#define BY2WD 4 /* bytes per word */ +#define BY2PG 4096 /* bytes per page */ +#define WD2PG (BY2PG/BY2WD) /* words per page */ +#define PGSHIFT 12 /* log(BY2PG) */ +#define PGROUND(s) (((s)+(BY2PG-1))&~(BY2PG-1)) + +#define MAXMACH 1 /* max # cpus system can run */ +#define CACHELINELOG 4 +#define CACHELINESZ (1<<CACHELINELOG) + +/* + * Time + */ +#define HZ (50) /* clock frequency */ +#define MS2HZ (1000/HZ) /* millisec per clock tick */ +#define TK2SEC(t) ((t)/HZ) /* ticks to seconds */ +#define TK2MS(t) ((((ulong)(t))*1000)/HZ) /* ticks to milliseconds */ +#define MS2TK(t) ((((ulong)(t))*HZ)/1000) /* milliseconds to ticks */ +#define MHz 1000000 + +/* + * Fundamental values + */ + +#define KZERO 0 /* bootstrap runs in real mode */ +#define MACHSIZE 4096 + +/* + * physical MMU + */ +#define KSEG0 0x20000000 +#define KSEGM 0xE0000000 /* mask to check which seg */ + +/* + * MSR bits + */ + +#define POW 0x40000 /* enable power mgmt */ +#define TGPR 0x20000 /* GPR0-3 remapped; 603/603e specific */ +#define ILE 0x10000 /* interrupts little endian */ +#define EE 0x08000 /* enable external/decrementer interrupts */ +#define PR 0x04000 /* =1, user mode */ +#define FPE 0x02000 /* enable floating point */ +#define ME 0x01000 /* enable machine check exceptions */ +#define FE0 0x00800 +#define SE 0x00400 /* single-step trace */ +#define BE 0x00200 /* branch trace */ +#define FE1 0x00100 +#define IP 0x00040 /* =0, vector to nnnnn; =1, vector to FFFnnnnn */ +#define IR 0x00020 /* enable instruction address translation */ +#define DR 0x00010 /* enable data address translation */ +#define RI 0x00002 /* exception is recoverable */ +#define LE 0x00001 /* little endian mode */ + +#define KMSR (ME|FE0|FE1|FPE) +#define UMSR (KMSR|PR|EE|IR|DR) + +/* + * MPC82x addresses + */ +#define BCSRMEM 0xFA400000 +#define FLASHMEM 0xFFC00000 +#define INTMEM 0xFA200000 + +#define DPRAM (INTMEM+0x2000) +#define DPLEN1 0x400 +#define DPLEN2 0x200 +#define DPLEN3 0x100 +#define DPBASE (DPRAM+DPLEN1) + +#define SCC1P (INTMEM+0x3C00) +#define I2CP (INTMEM+0x3C80) +#define MISCP (INTMEM+0x3CB0) +#define IDMA1P (INTMEM+0x3CC0) +#define SCC2P (INTMEM+0x3D00) +#define SCC3P (INTMEM+0x3E00) +#define SCC4P (INTMEM+0x3F00) +#define SPIP (INTMEM+0x3D80) +#define TIMERP (INTMEM+0x3DB0) +#define SMC1P (INTMEM+0x3E80) +#define DSP1P (INTMEM+0x3EC0) +#define SMC2P (INTMEM+0x3F80) +#define DSP2P (INTMEM+0x3FC0) + +#define KEEP_ALIVE_KEY 0x55ccaa33 /* clock and rtc register key */ diff --git a/os/boot/rpcg/mkfile b/os/boot/rpcg/mkfile new file mode 100644 index 00000000..85b1e1f2 --- /dev/null +++ b/os/boot/rpcg/mkfile @@ -0,0 +1,120 @@ +objtype=power +OBJTYPE=power # always +<../../../mkconfig +SYSTARG=$OSTARG # always +<$ROOT/mkfiles/mkfile-$SYSTARG-$OBJTYPE +INSTALLDIR=$ROOT/Inferno/$OBJTYPE/bin #path of directory where kernel is installed +CONF=rpcg # selects board dependent code +TARG=qb$CONF +OFILES=\ + l.$O\ + arch$CONF.$O\ + devuart.$O\ + uartboot.$O\ + alarm.$O\ + bootp.$O\ + clock.$O\ + conf.$O\ + console.$O\ + cpm.$O\ + defont0.$O\ + donprint.$O\ + dosboot.$O\ + devether.$O\ + etherscc.$O\ + fblt.$O\ + gbitbltclip.$O\ + flash.$O\ + main.$O\ + i2c.$O\ + plan9boot.$O\ + qio.$O\ + rmap.$O\ + screen.$O\ + init$CONF.$O\ + trap.$O\ + zqs.$O\ + +HFILES=\ + boot.h\ + dat.h\ + fns.h\ + io.h\ + lib.h\ + mem.h\ + squeeze.h\ + gnot.h\ + arch$CONF.h\ + +LIBS=\ + kern\ + +LIBDIRS=$LIBS +LIBNAMES=${LIBS:%=lib%.a} +LIBFILES=${LIBS:%=$ROOT/$TARGMODEL/$OBJTYPE/lib/lib%.a} + +#all:NV: $TARG k.mx f.mx +all:NV: $TARG +install:V: $INSTALLDIR/$TARG +installall:V: $INSTALLDIR/$TARG + +$INSTALLDIR/%: % + rm -f $INSTALLDIR/$stem && cp $stem $INSTALLDIR/$stem + +$TARG: $OFILES $LIBNAMES + $LD -o $target -l -T0x140000 -R4 $OFILES $LIBFILES + ls -l $target + +qbrom$CONF: $OFILES $LIBNAMES + $LD -o $target -l -T0xFFC20100 -R0 -D0x140000 $OFILES $LIBFILES + +k.mx: $TARG + ms2 -S 0x100 -a 0x140000 -3 -p 4 $TARG >$target + +f.mx: qbrom$CONF + ms2 -S 0x100 -a 0xFFC20100 -3 -p 4 $prereq >$target + +g.mx: qbrom$CONF + ms2 -S 0x100 -a 0x10000 -3 -p 4 $prereq >$target + +%.$O: %.s + $AS -Dconf$CONF $stem.s + +%.$O: %.c + $CC $CFLAGS $stem.c + +%.$O: $HFILES + +lib%.a:V: $SHELLTYPE-lib%.a + +rc-lib%.a nt-lib%.a:VQ: + echo '@{builtin cd ' $ROOT/lib$stem ';mk SHELLTYPE=$SHELLTYPE SYSTARG=$SYSTARG OBJTYPE=$OBJTYPE install}' + @{builtin cd $ROOT/lib$stem ;mk 'SHELLTYPE='$SHELLTYPE 'SYSTARG='$SYSTARG 'OBJTYPE='$OBJTYPE install} + +sh-lib%.a:VQ: + echo "(cd $ROOT/lib$stem ; mk SHELLTYPE=$SHELLTYPE SYSTARG=$SYSTARG OBJTYPE=$OBJTYPE install)" + (cd $ROOT/lib$stem ; mk SHELLTYPE=$SHELLTYPE SYSTARG=$SYSTARG OBJTYPE=$OBJTYPE install) + +clock.$O floppy.$O trap.$O: ureg.h +conf.$O dosboot.$O main.$O: dosfs.h +ether.$O etherscc.$O: etherif.h +bootp.$O: ip.h + +clean:V: + rm -f *.[$OS] [$OS].out y.tab.? y.debug y.output $TARG qboot k.mx f.mx romboot + +nuke-sh:QV: + for i in $LIBDIRS + do + echo "(cd $ROOT/lib$i ; mk SHELLTYPE=$SHELLTYPE SYSTARG=$SYSTARG OBJTYPE=$OBJTYPE nuke)" + (cd $ROOT/lib$i; mk 'SHELLTYPE='$SHELLTYPE 'SYSTARG='$SYSTARG 'OBJTYPE='$OBJTYPE nuke) + done + +nuke-rc nuke-nt:QV: + for (i in $LIBDIRS) + { + echo '@{cd $ROOT/lib$i ; mk SHELLTYPE=$SHELLTYPE SYSTARG=$SYSTARG OBJTYPE=$OBJTYPE nuke}' + @{cd $ROOT/lib$i; mk 'SHELLTYPE='$SHELLTYPE 'SYSTARG='$SYSTARG 'OBJTYPE='$OBJTYPE nuke} + } + +nuke:V: clean nuke-$SHELLTYPE diff --git a/os/boot/rpcg/ms2.c b/os/boot/rpcg/ms2.c new file mode 100644 index 00000000..ce96df78 --- /dev/null +++ b/os/boot/rpcg/ms2.c @@ -0,0 +1,179 @@ +#include <u.h> +#include <libc.h> +#include <bio.h> +#include <mach.h> + +void record(uchar*, int); +void usage(void); +void dosegment(long, int); +void trailer(ulong); + +enum +{ + Recordsize = 32, +}; + +int dsegonly; +int supressend; +int binary; +int addr4; +ulong addr; +ulong psize = 4096; +ulong startaddr = 0x030000; +Biobuf stdout; +Biobuf bio; + +void +main(int argc, char **argv) +{ + Dir dir; + Fhdr f; + int fd; + + ARGBEGIN{ + case 'd': + dsegonly++; + break; + case 's': + supressend++; + break; + case 'a': + addr = strtoul(ARGF(), 0, 0); + break; + case 'p': + psize = strtoul(ARGF(), 0, 0); + break; + case 'b': + binary++; + break; + case 'S': + startaddr = strtoul(ARGF(), 0, 0); + break; + case '4': + addr4++; + break; + default: + usage(); + }ARGEND + + if(argc != 1) + usage(); + + Binit(&stdout, 1, OWRITE); + + fd = open(argv[0], OREAD); + if(fd < 0) { + fprint(2, "ms2: open %s: %r\n", argv[0]); + exits("open"); + } + + if(binary) { + if(dirfstat(fd, &dir) < 0) { + fprint(2, "ms2: stat failed %r"); + exits("dirfstat"); + } + Binit(&bio, fd, OREAD); + dosegment(0, dir.length); + if(supressend == 0) + trailer(startaddr); + Bterm(&stdout); + Bterm(&bio); + exits(0); + } + + if(crackhdr(fd, &f) == 0){ + fprint(2, "ms2: bad magic: %r\n"); + exits("magic"); + } + seek(fd, 0, 0); + + Binit(&bio, fd, OREAD); + + if(dsegonly) + dosegment(f.datoff, f.datsz); + else { + dosegment(f.txtoff, f.txtsz); + addr = (addr+(psize-1))&~(psize-1); + dosegment(f.datoff, f.datsz); + } + + if(supressend == 0) + trailer(startaddr); + + Bterm(&stdout); + Bterm(&bio); + exits(0); +} + +void +dosegment(long foff, int len) +{ + int l, n; + uchar buf[2*Recordsize]; + + Bseek(&bio, foff, 0); + for(;;) { + l = len; + if(l > Recordsize) + l = Recordsize; + n = Bread(&bio, buf, l); + if(n == 0) + break; + if(n < 0) { + fprint(2, "ms2: read error: %r\n"); + exits("read"); + } + record(buf, l); + len -= l; + } +} + +void +record(uchar *s, int l) +{ + int i; + ulong cksum; + + if(addr4 || addr & (0xFF<<24)){ + Bprint(&stdout, "S3%.2X%.8luX", l+5, addr); + cksum = l+5; + cksum += (addr>>24)&0xff; + }else{ + Bprint(&stdout, "S2%.2X%.6X", l+4, addr); + cksum = l+4; + } + cksum += addr&0xff; + cksum += (addr>>8)&0xff; + cksum += (addr>>16)&0xff; + + for(i = 0; i < l; i++) { + cksum += *s; + Bprint(&stdout, "%.2X", *s++); + } + Bprint(&stdout, "%.2X\n", (~cksum)&0xff); + addr += l; +} + +void +trailer(ulong a) +{ + ulong cksum; + + cksum = 0; + if(addr4 || a & (0xFF<<24)){ + Bprint(&stdout, "S7%.8luX", a); + cksum += (a>>24)&0xff; + }else + Bprint(&stdout, "S9%.6X", a); + cksum += a&0xff; + cksum += (a>>8)&0xff; + cksum += (a>>16)&0xff; + Bprint(&stdout, "%.2X\n", (~cksum)&0xff); +} + +void +usage(void) +{ + fprint(2, "usage: ms2 [-ds] [-a address] [-p pagesize] ?.out\n"); + exits("usage"); +} diff --git a/os/boot/rpcg/plan9boot.c b/os/boot/rpcg/plan9boot.c new file mode 100644 index 00000000..047474e3 --- /dev/null +++ b/os/boot/rpcg/plan9boot.c @@ -0,0 +1,96 @@ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" + +char *premature = "premature EOF\n"; + +/* + * read in a segment + */ +static long +readseg(int dev, long (*read)(int, void*, long), long len, long addr) +{ + char *a; + long n, sofar; + + a = (char *)addr; + for(sofar = 0; sofar < len; sofar += n){ + n = 8*1024; + if(len - sofar < n) + n = len - sofar; + n = (*read)(dev, a + sofar, n); + if(n <= 0) + break; + print("."); + } + return sofar; +} + +/* + * boot + */ +int +plan9boot(int dev, long (*seek)(int, long), long (*read)(int, void*, long)) +{ + long n; + long addr; + void (*b)(void); + Exec *ep; + + if((*seek)(dev, 0) < 0) + return -1; + + /* + * read header + */ + ep = (Exec *) ialloc(sizeof(Exec), 0); + n = sizeof(Exec); + if(readseg(dev, read, n, (long) ep) != n){ + print(premature); + return -1; + } + if(GLLONG(ep->magic) != Q_MAGIC){ + print("bad magic 0x%lux not a plan 9 executable!\n", GLLONG(ep->magic)); + return -1; + } + + /* + * read text + */ + addr = PADDR(GLLONG(ep->entry)); + n = GLLONG(ep->text); + print("%d", n); + if(readseg(dev, read, n, addr) != n){ + print(premature); + return -1; + } + + /* + * read data (starts at first page after kernel) + */ + addr = PGROUND(addr+n); + n = GLLONG(ep->data); + print("+%d@%8.8lux", n, addr); + if(readseg(dev, read, n, addr) != n){ + print(premature); + return -1; + } + + /* + * bss and entry point + */ + print("+%d\nstart at 0x%lux\n", GLLONG(ep->bss), GLLONG(ep->entry)); + uartwait(); + scc2stop(); + splhi(); + + /* + * Go to new code. It's up to the program to get its PC relocated to + * the right place. + */ + b = (void (*)(void))(PADDR(GLLONG(ep->entry))); + (*b)(); + return 0; +} diff --git a/os/boot/rpcg/qbromrpcg b/os/boot/rpcg/qbromrpcg Binary files differnew file mode 100755 index 00000000..8b2fe7d8 --- /dev/null +++ b/os/boot/rpcg/qbromrpcg diff --git a/os/boot/rpcg/qio.c b/os/boot/rpcg/qio.c new file mode 100644 index 00000000..e014433e --- /dev/null +++ b/os/boot/rpcg/qio.c @@ -0,0 +1,128 @@ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" + +struct Queue { + Block* first; + Block* last; + void (*kick)(void*); + void* arg; + long len; +}; + +Block * +iallocb(int n) +{ + Block *b; + + b = (Block*)malloc(sizeof(Block)+n); + b->data = (uchar*)b + sizeof(Block); + b->rp = b->wp = b->data; + b->lim = b->data + n; + b->next = 0; + b->magic = 0xcafebee0; + return b; +} + +void +freeb(Block *b) +{ + if(b){ + if(b->magic != 0xcafebee0) + panic("freeb"); + b->magic = 0; + b->next = (Block*)0xdeadbabe; + free(b); + } +} + +Queue * +qopen(int limit, int msg, void (*kick)(void*), void *arg) +{ + Queue *q; + + USED(limit, msg); + q = (Queue*)malloc(sizeof(Queue)); + q->first = q->last = 0; + q->kick = kick; + q->arg = arg; + q->len = 0; + return q; +} + +Block * +qget(Queue *q) +{ + int s; + Block *b; + + s = splhi(); + if((b = q->first) != 0){ + q->first = b->next; + b->next = 0; + q->len -= BLEN(b); + if(q->len < 0) + panic("qget"); + } + splx(s); + return b; +} + +void +qbwrite(Queue *q, Block *b) +{ + int s; + + s = splhi(); + b->next = 0; + if(q->first == 0) + q->first = b; + else + q->last->next = b; + q->last = b; + q->len += BLEN(b); + splx(s); + if(q->kick) + q->kick(q->arg); +} + +long +qlen(Queue *q) +{ + return q->len; +} + +int +qbgetc(Queue *q) +{ + Block *b; + int s, c; + + c = -1; + s = splhi(); + while(c < 0 && (b = q->first) != nil){ + if(b->rp < b->wp){ + c = *b->rp++; + q->len--; + } + if(b->rp >= b->wp){ + q->first = b->next; + b->next = nil; + } + } + splx(s); + return c; +} + +void +qbputc(Queue *q, int c) +{ + Block *b; + + b = iallocb(1); + *b->wp++ = c; + qbwrite(q, b); +} diff --git a/os/boot/rpcg/rmap.c b/os/boot/rpcg/rmap.c new file mode 100644 index 00000000..8b8a0bef --- /dev/null +++ b/os/boot/rpcg/rmap.c @@ -0,0 +1,104 @@ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" + +void +mapinit(RMap *rmap, Map *map, int size) +{ + lock(rmap); + rmap->map = map; + rmap->mapend = map+(size/sizeof(Map)); + unlock(rmap); +} + +void +mapfree(RMap* rmap, ulong addr, int size) +{ + Map *mp; + ulong t; + + if(size <= 0) + return; + + lock(rmap); + for(mp = rmap->map; mp->addr <= addr && mp->size; mp++) + ; + + if(mp > rmap->map && (mp-1)->addr+(mp-1)->size == addr){ + (mp-1)->size += size; + if(addr+size == mp->addr){ + (mp-1)->size += mp->size; + while(mp->size){ + mp++; + (mp-1)->addr = mp->addr; + (mp-1)->size = mp->size; + } + } + } + else{ + if(addr+size == mp->addr && mp->size){ + mp->addr -= size; + mp->size += size; + } + else do{ + if(mp >= rmap->mapend){ + print("mapfree: %s: losing 0x%uX, %d\n", + rmap->name, addr, size); + break; + } + t = mp->addr; + mp->addr = addr; + addr = t; + t = mp->size; + mp->size = size; + mp++; + }while(size = t); + } + unlock(rmap); +} + +ulong +mapalloc(RMap* rmap, ulong addr, int size, int align) +{ + Map *mp; + ulong maddr, oaddr; + + lock(rmap); + for(mp = rmap->map; mp->size; mp++){ + maddr = mp->addr; + + if(addr){ + if(maddr > addr) + continue; + if(addr+size > maddr+mp->size) + break; + maddr = addr; + } + + if(align > 0) + maddr = ((maddr+align-1)/align)*align; + if(mp->addr+mp->size-maddr < size) + continue; + + oaddr = mp->addr; + mp->addr = maddr+size; + mp->size -= maddr-oaddr+size; + if(mp->size == 0){ + do{ + mp++; + (mp-1)->addr = mp->addr; + }while((mp-1)->size = mp->size); + } + + unlock(rmap); + if(oaddr != maddr) + mapfree(rmap, oaddr, maddr-oaddr); + + return maddr; + } + unlock(rmap); + + return 0; +} diff --git a/os/boot/rpcg/screen.c b/os/boot/rpcg/screen.c new file mode 100644 index 00000000..ec420ee9 --- /dev/null +++ b/os/boot/rpcg/screen.c @@ -0,0 +1,242 @@ +#include "all.h" +#include <libg.h> +#include <gnot.h> + +enum { + Colldepth = 3, + Colmaxx = 640, + Colmaxxvis = 640, + Colmaxy = 480, +}; + +#define MINX 8 + +extern GSubfont defont0; + +struct{ + Point pos; + int bwid; +}out; + +typedef struct Mode Mode; +struct Mode { + int x; + int y; + int d; + char* aperture; + int apsize; +}; + +GBitmap gscreen; +Point gchar(GBitmap*, Point, GFont*, int, Fcode); +int setcolor(ulong, ulong, ulong, ulong); +static void lcdinit(Mode*); + +void +screeninit(void) +{ + Mode m; + + m.x = Colmaxx; + m.y = Colmaxy; + m.d = Colldepth; + m.aperture = 0; + lcdinit(&m); + if(m.aperture == 0) + return; + gscreen.ldepth = 3; + gscreen.base = (ulong*)m.aperture; + gscreen.width = Colmaxx/BY2WD; + gscreen.r = Rect(0, 0, Colmaxxvis, Colmaxy); + gscreen.clipr = gscreen.r; + /* + * For now, just use a fixed colormap: + * 0 == white and 255 == black + */ + setcolor(0, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF); + setcolor(255, 0x00000000, 0x00000000, 0x00000000); + + gbitblt(&gscreen, Pt(0, 0), &gscreen, gscreen.r, Zero); + out.pos.x = MINX; + out.pos.y = 0; + out.bwid = defont0.info[' '].width; +} + +void +screenputc(int c) +{ + Fontchar *i; + Point p; + + if(gscreen.base == nil) + return; + switch(c){ + case '\n': + out.pos.x = MINX; + out.pos.y += defont0.height; + if(out.pos.y > gscreen.r.max.y-defont0.height) + out.pos.y = gscreen.r.min.y; + gbitblt(&gscreen, Pt(0, out.pos.y), &gscreen, + Rect(0, out.pos.y, gscreen.r.max.x, out.pos.y+2*defont0.height), + Zero); + break; + case '\t': + out.pos.x += (8-((out.pos.x-MINX)/out.bwid&7))*out.bwid; + if(out.pos.x >= gscreen.r.max.x) + screenputc('\n'); + break; + case '\b': + if(out.pos.x >= out.bwid+MINX){ + out.pos.x -= out.bwid; + screenputc(' '); + out.pos.x -= out.bwid; + } + break; + default: + if(out.pos.x >= gscreen.r.max.x-out.bwid) + screenputc('\n'); + c &= 0x7f; + if(c <= 0 || c >= defont0.n) + break; + i = defont0.info + c; + p = out.pos; + gbitblt(&gscreen, Pt(p.x+i->left, p.y), defont0.bits, + Rect(i[0].x, 0, i[1].x, defont0.height), + S); + out.pos.x = p.x + i->width; + break; + } +} + +void +screenputs(char *s, int n) +{ + while(n-- > 0) + screenputc(*s++); +} + +/* + * See section 5.2.1 (page 5-6) of the MPC823 manual + */ +static uchar lcdclock[17] = { /* (a<<2)|b => divisor of (1<<a)*((b<<1)+1) */ + 0, 0, (1<<2), 1, + (2<<2), 2, (1<<2)|1, 3, + (3<<2), (1<<2)|2, (1<<2)|2, (2<<2)|1, + (2<<2)|1, (1<<2)|3, (1<<2)|3, (4<<2), + (4<<2) +}; + +/* + * support for the Sharp LQ64D341 TFT colour display + */ + +enum { + COLS = 640, + ROWS = 480, + LDEPTH = 3, /* screen depth */ + LCDFREQ = 25000000, + + /* lccr */ + ClockLow = 1<<11, + OELow = 1<<10, + HsyncLow = 1<<9, + VsyncLow = 1<<8, + DataLow = 1<<7, + Passive8 = 1<<4, + DualScan = 1<<3, + IsColour = 1<<2, + IsTFT = 1<<1, + Enable = 1<<0, + + /* lchcr */ + BigEndian = 1<<24, + AT7 = 7<<21, /* access type */ + + /* sdcr */ + LAM = 1<<6, /* ``LCD aggressive mode'' */ +}; + +/* + * TO DO: most of the data could come from a table + */ +static void +lcdinit(Mode *mode) +{ + IMM *io; + int i, d; + long hz; + + io = m->iomem; + mode->y = ROWS; + mode->x = COLS; + mode->d = LDEPTH; + mode->aperture = ialloc(mode->x*mode->y, 16); + mode->apsize = mode->x*mode->y; + + io->sdcr &= ~LAM; /* MPC823 errata: turn off LAM before disabling controller */ + io->lcfaa = PADDR(mode->aperture); + io->lccr = (((mode->x*mode->y*(1<<LDEPTH)+127)/128) << 17) | (LDEPTH << 5) | IsColour | IsTFT | OELow | VsyncLow | ClockLow; + + switch(LDEPTH){ + default: + case 0: + /* monochrome/greyscale identity map */ + for(i=0; i<16; i++) + io->lcdmap[i] = i; + break; + case 2: + /* 4-bit grey scale map */ + for(i=0; i<16; i++) + io->lcdmap[0] = (i<<8)|(i<<4)|i; + break; + case 3: + /* 8-bit linear map */ + for(i=0; i<256; i++) + io->lcdmap[i] = (i<<8)|(i<<4)|i; + break; + } + + io->lcvcr = (mode->y << 11) | (1<<28) | 33; /* 2 line vsync pulse, 34 line wait between frames */ + io->lchcr = (mode->x<<10) | BigEndian | 228; /* clock cycles between lines */ + + hz = m->cpuhz; + d = hz/LCDFREQ; + if(hz/d > LCDFREQ) + d++; + if(d >= 16) + d = 16; + + /* + * enable LCD outputs + */ + io->pddat = 0; + io->pdpar = 0x1fff; +io->pdpar &= ~SIBIT(6); /* 823 bug fix? */ + io->pddir = 0x1fff; + io->pbpar |= IBIT(31) | IBIT(19) | IBIT(17); + io->pbdir |= IBIT(31) | IBIT(19) | IBIT(17); + io->pbodr &= ~(IBIT(31) | IBIT(19) | IBIT(17)); + + eieio(); + io->sccrk = KEEP_ALIVE_KEY; + eieio(); + io->sccr = (io->sccr & ~0x1F) | lcdclock[d]; + eieio(); + io->sccrk = ~KEEP_ALIVE_KEY; + eieio(); + gscreen.width = gscreen.width; /* access external memory before enabling (mpc823 errata) */ + io->lcsr = 7; /* clear status */ + eieio(); + io->lccr |= Enable; + archbacklight(1); +} + +int +setcolor(ulong p, ulong r, ulong g, ulong b) +{ + r >>= 28; + g >>= 28; + b >>= 28; + m->iomem->lcdmap[~p&0xFF] = (r<<8) | (g<<4) | b; /* TO DO: it's a function of the ldepth */ + return 1; +} diff --git a/os/boot/rpcg/sload b/os/boot/rpcg/sload Binary files differnew file mode 100755 index 00000000..0e2a3458 --- /dev/null +++ b/os/boot/rpcg/sload diff --git a/os/boot/rpcg/sload.c b/os/boot/rpcg/sload.c new file mode 100644 index 00000000..0eb02805 --- /dev/null +++ b/os/boot/rpcg/sload.c @@ -0,0 +1,71 @@ +/* + * send S records to rpcg + */ + +#include <u.h> +#include <libc.h> +#include <bio.h> + +static int dbg; +static char buf[2048]; +static int run=1; +static void stuffbym(char*, int, int); +static void getdot(void); + +void +main(int argc, char **argv) +{ + int n; + char *l; + Biobuf *f; + static int p; + + ARGBEGIN{ + case 'd': dbg++; break; + case 'n': run=0; break; + }ARGEND + + f = Bopen(*argv? *argv: "k.mx", OREAD); + if(f == 0) { + fprint(2, "sload: cannot open k.mx: %r\n"); + exits("sload"); + } + getdot(); + while((l = Brdline(f, '\n')) != 0) { + l[Blinelen(f)-1] = '\r'; + stuffbym(l, Blinelen(f), 16); + getdot(); + if(++p % 25 == 0) + write(2, ".", 1); + } + exits(0); +} + +static void +stuffbym(char *l, int n, int m) +{ + int nr, ns; + + while(n > 0) { + ns = n; + if(ns > m) + ns = m; + write(1, l, ns); + l += ns; + n -= ns; + } +} + +static void +getdot(void) +{ + char c; + + for(;;){ + if(read(0, &c, 1) != 1) + exits("bang"); + write(2, &c, 1); + if(c == '.') + break; + } +} diff --git a/os/boot/rpcg/squeeze.h b/os/boot/rpcg/squeeze.h new file mode 100644 index 00000000..b06c1b79 --- /dev/null +++ b/os/boot/rpcg/squeeze.h @@ -0,0 +1,34 @@ + +/* + * squeezed file format: + * Sqhdr + * original Exec header + * two Squeeze tables + * squeezed segment + * unsqueezed segment, if any + */ +#define SQMAGIC (ulong)0xFEEF0F1E + +typedef struct Sqhdr Sqhdr; +struct Sqhdr { + uchar magic[4]; /* SQMAGIC */ + uchar text[4]; /* squeezed length of text (excluding tables) */ + uchar data[4]; /* squeezed length of data (excluding tables) */ + uchar asis[4]; /* length of unsqueezed segment */ + uchar toptxt[4]; /* value for 0 encoding in text */ + uchar topdat[4]; /* value for 0 encoding in data */ + uchar sum[4]; /* simple checksum of unsqueezed data */ + uchar flags[4]; +}; +#define SQHDRLEN (8*4) + +/* + * certain power instruction types are rearranged by sqz + * so as to move the variable part of the instruction word to the + * low order bits. note that the mapping is its own inverse. + */ +#define QREMAP(X)\ + switch((X)>>26){\ + case 19: case 31: case 59: case 63:\ + (X) = (((X) & 0xFC00F801) | (((X)>>15)&0x7FE) | (((X)&0x7FE)<<15));\ + } diff --git a/os/boot/rpcg/trap.c b/os/boot/rpcg/trap.c new file mode 100644 index 00000000..3440ee1f --- /dev/null +++ b/os/boot/rpcg/trap.c @@ -0,0 +1,233 @@ +#include "boot.h" + +enum +{ + Maxhandler= 32+16, /* max number of interrupt handlers */ +}; + +typedef struct Handler Handler; +struct Handler +{ + void (*r)(Ureg*, void*); + void *arg; + Handler *next; + int edge; +}; + +struct +{ + Handler *ivec[128]; + Handler h[Maxhandler]; + int free; +} halloc; + +char *excname[] = { + "reserved 0", + "system reset", + "machine check", + "data access", + "instruction access", + "external interrupt", + "alignment", + "program exception", + "floating-point unavailable", + "decrementer", + "reserved A", + "reserved B", + "system call", + "trace trap", + "floating point assist", + "reserved F", + "software emulation", + "ITLB miss", + "DTLB miss", + "ITLB error", + "DTLB error", +}; + +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 void intr(Ureg*); + +void +sethvec(int v, void (*r)(void)) +{ + ulong *vp, pa, o; + + if((ulong)r & 3) + panic("sethvec"); + vp = (ulong*)KADDR(v); + vp[0] = 0x7c1043a6; /* MOVW R0, SPR(SPRG0) */ + vp[1] = 0x7c0802a6; /* MOVW LR, R0 */ + vp[2] = 0x7c1243a6; /* MOVW R0, SPR(SPRG2) */ + pa = PADDR(r); + o = pa >> 25; + if(o != 0 && o != 0x7F){ + /* a branch too far: running from ROM */ + vp[3] = (15<<26)|(pa>>16); /* MOVW $r&~0xFFFF, R0 */ + vp[4] = (24<<26)|(pa&0xFFFF); /* OR $r&0xFFFF, R0 */ + vp[5] = 0x7c0803a6; /* MOVW R0, LR */ + vp[6] = 0x4e800021; /* BL (LR) */ + }else + vp[3] = (18<<26)|(pa&0x3FFFFFC)|3; /* bla */ +} + +#define LEV(n) (((n)<<1)|1) +#define IRQ(n) (((n)<<1)|0) + +void +setvec(int v, void (*r)(Ureg*, void*), void *arg) +{ + Handler *h; + IMM *io; + + if(halloc.free >= Maxhandler) + panic("out of interrupt handlers"); + v -= VectorPIC; + h = &halloc.h[halloc.free++]; + h->next = halloc.ivec[v]; + h->r = r; + h->arg = arg; + halloc.ivec[v] = h; + + /* + * enable corresponding interrupt in SIU/CPM + */ + + io = m->iomem; + if(v >= VectorCPIC){ + v -= VectorCPIC; + io->cimr |= 1<<(v&0x1F); + } + else if(v >= VectorIRQ) + io->simask |= 1<<(31-IRQ(v&7)); + else + io->simask |= 1<<(31-LEV(v)); +} + +void +trapinit(void) +{ + int i; + IMM *io; + + io = m->iomem; + io->sypcr &= ~(3<<2); /* disable watchdog (821/823) */ + io->simask = 0; /* mask all */ + io->siel = ~0; /* edge sensitive, wake on all */ + io->cicr = 0; /* disable CPM interrupts */ + io->cipr = ~0; /* clear all interrupts */ + io->cimr = 0; /* mask all events */ + io->cicr = (0xE1<<16)|(CPIClevel<<13)|(0x1F<<8); + io->cicr |= 1 << 7; /* enable */ + io->tbscrk = KEEP_ALIVE_KEY; + io->tbscr = 1; /* TBE */ + io->simask |= 1<<(31-LEV(CPIClevel)); /* CPM's level */ + io->tbk = KEEP_ALIVE_KEY; + eieio(); + putdec(~0); + + /* + * set all exceptions to trap + */ + for(i = 0x0; i < 0x3000; i += 0x100) + sethvec(i, exception); +} + +void +dumpregs(Ureg *ur) +{ + int i; + ulong *l; + l = &ur->cause; + for(i=0; i<sizeof regname/sizeof(char*); i+=2, l+=2) + print("%s\t%.8lux\t%s\t%.8lux\n", regname[i], l[0], regname[i+1], l[1]); +} + +void +trap(Ureg *ur) +{ + int c; + + c = ur->cause >> 8; + switch(c){ + default: + {extern int predawn; predawn = 1;} + if(c < 0 || c >= nelem(excname)) + print("exception/interrupt #%x\n", c); + else + print("exception %s\n", excname[c]); + dumpregs(ur); + /* spllo(); */ + print("^P to reset\n"); + for(;;) + ; + + case 0x09: /* decrementer */ + clockintr(ur, 0); + return; + + case 0x05: /* external interrupt */ + intr(ur); + break; + } +} + +static void +intr(Ureg *ur) +{ + int b, v; + Handler *h; + IMM *io; + + io = m->iomem; + b = io->sivec>>2; + v = b>>1; + if(b & 1) { + if(v == CPIClevel){ + io->civr = 1; + eieio(); + v = VectorCPIC+(io->civr>>11); + } + }else + v += VectorIRQ; + h = halloc.ivec[v]; + if(h == nil){ + for(;;) + ; + //print("unknown interrupt %d pc=0x%lux\n", v, ur->pc); + return; + } + if(h->edge) + io->sipend |= 1<<(31-b); + /* + * call the interrupt handlers + */ + do { + (*h->r)(ur, h->arg); + h = h->next; + } while(h != nil); + if(v >= VectorCPIC) + io->cisr |= 1<<(v-VectorCPIC); +} diff --git a/os/boot/rpcg/uartboot.c b/os/boot/rpcg/uartboot.c new file mode 100644 index 00000000..0b11b5d5 --- /dev/null +++ b/os/boot/rpcg/uartboot.c @@ -0,0 +1,189 @@ +#include "boot.h" + +/* + * this doesn't yet use the crc + */ + +typedef struct Uboot Uboot; +struct Uboot { + Queue* iq; + Block* partial; + ulong csum; + long bno; + uchar buf[64]; + int nleft; + int ntimeout; +}; + +static Uboot uboot; +ulong crc32(void *buf, int n, ulong crc); + +static void +uartbrecv(uchar *p, int n) +{ + Uboot *ub; + Block *b; + + ub = &uboot; + if(n > 0 && ub->iq != nil){ + b = iallocb(n); + memmove(b->wp, p, n); + b->wp += n; + qbwrite(ub->iq, b); + } +} + +int +uartinit(void) +{ + return 1<<0; +} + +Partition* +setuartpart(int, char *s) +{ + static Partition pp[1]; + + if(strcmp(s, "boot") != 0 && strcmp(s, "disk") != 0) + return 0; + pp[0].start = 0; + pp[0].end = 2*1024*1024; + strcpy(pp[0].name, "boot"); + return pp; +} + +long +uartseek(int, long) +{ + /* start the boot */ + if(uboot.iq == nil) + uboot.iq = qopen(64*1024, 0, 0, 0); + if(uboot.partial){ + freeb(uboot.partial); + uboot.partial = 0; + } + print("uart: start transmission\n"); + uartsetboot(uartbrecv); + uboot.csum = ~0; + uboot.bno = 0; + uboot.nleft = 0; + uboot.ntimeout = 0; + return 0; +} + +static long +uartreadn(void *buf, int nb) +{ + ulong start; + Uboot *ub; + int l; + Block *b; + uchar *p; + + p = buf; + ub = &uboot; + start = m->ticks; + while(nb > 0){ + b = ub->partial; + ub->partial = nil; + if(b == nil){ + ub->ntimeout = 0; + while((b = qget(ub->iq)) == 0){ + if(TK2MS(m->ticks - start) >= 15*1000){ + if(++ub->ntimeout >= 3){ + print("uart: timeout\n"); + return 0; + } + uartputs("n", 1); + } + } + } + l = BLEN(b); + if(l > nb) + l = nb; + memmove(p, b->rp, l); + b->rp += l; + if(b->rp >= b->wp) + freeb(b); + else + ub->partial = b; + nb -= l; + p += l; + } + return p-(uchar*)buf; +} + +long +uartread(int, void *buf, long n) +{ + uchar *p; + int l; + static uchar lbuf[64]; + + p = buf; + if((l = uboot.nleft) > 0){ + if(l > n) + l = n; + uboot.nleft -= l; + memmove(p, uboot.buf, l); + p += l; + n -= l; + } + while(n > 0){ + l = uartreadn(lbuf, sizeof(lbuf)); + if(l < sizeof(lbuf)) + return 0; + if(l > n){ + uboot.nleft = l-n; + memmove(uboot.buf, lbuf+n, uboot.nleft); + l = n; + } + memmove(p, lbuf, l); + n -= l; + p += l; + uboot.bno++; + uartputs("y", 1); + } + return p-(uchar*)buf; +} + +/* + * from Rob Warnock + */ +static ulong crc32tab[256]; /* initialised on first call to crc32 */ + +enum { + CRC32POLY = 0x04c11db7 /* AUTODIN II, Ethernet, & FDDI */ +}; + +/* + * Build auxiliary table for parallel byte-at-a-time CRC-32. + */ +static void +initcrc32(void) +{ + int i, j; + ulong c; + + for(i = 0; i < 256; i++) { + for(c = i << 24, j = 8; j > 0; j--) + if(c & (1<<31)) + c = (c<<1) ^ CRC32POLY; + else + c <<= 1; + crc32tab[i] = c; + } +} + +ulong +crc32(void *buf, int n, ulong crc) +{ + uchar *p; + + if(crc32tab[1] == 0) + initcrc32(); + crc = ~crc; + for(p = buf; --n >= 0;) + crc = (crc << 8) ^ crc32tab[(crc >> 24) ^ *p++]; + return ~crc; +} diff --git a/os/boot/rpcg/ureg.h b/os/boot/rpcg/ureg.h new file mode 100644 index 00000000..7ccdb492 --- /dev/null +++ b/os/boot/rpcg/ureg.h @@ -0,0 +1,43 @@ +struct Ureg +{ + ulong cause; + union { ulong srr1; ulong status;}; + ulong pc; /* SRR0 */ + ulong pad; + ulong lr; + ulong cr; + ulong xer; + ulong ctr; + ulong r0; + union{ ulong r1; ulong sp; ulong usp; }; + ulong r2; + ulong r3; + ulong r4; + ulong r5; + ulong r6; + ulong r7; + ulong r8; + ulong r9; + ulong r10; + ulong r11; + ulong r12; + ulong r13; + ulong r14; + ulong r15; + ulong r16; + ulong r17; + ulong r18; + ulong r19; + ulong r20; + ulong r21; + ulong r22; + ulong r23; + ulong r24; + ulong r25; + ulong r26; + ulong r27; + ulong r28; + ulong r29; + ulong r30; + ulong r31; +}; diff --git a/os/boot/rpcg/zqs.c b/os/boot/rpcg/zqs.c new file mode 100644 index 00000000..b6296786 --- /dev/null +++ b/os/boot/rpcg/zqs.c @@ -0,0 +1,234 @@ +#include "boot.h" +#include "squeeze.h" + +/* + * for details of `unsqueeze' see: + * + * %A Mark Taunton + * %T Compressed Executables: An Exercise in Thinking Small + * %P 385-404 + * %I USENIX + * %B USENIX Conference Proceedings + * %D Summer 1991 + * %C Nashville, TN + * + * several of the unimplemented improvements described in the paper + * have been implemented here + * + * there is a further transformation on the powerpc (QFLAG!=0) to shuffle bits + * in certain instructions so as to push the fixed bits to the top of the word. + */ + +#define EXECHDRLEN (8*4) + +typedef struct Squeeze Squeeze; +struct Squeeze { + int n; + ulong tab[7*256]; +}; + +#define GET4(p) (((((((p)[0]<<8)|(p)[1])<<8)|(p)[2])<<8)|(p)[3]) + +/* + * for speed of unsqueezing from Flash, certain checks are + * not done inside the loop (as they would be in the unsqueeze program zqs), + * but instead the checksum is expected to catch corrupted files. + * in fact the Squeeze array bounds can't be exceeded in practice + * because the tables are always full for a squeezed kernel. + */ +enum { + QFLAG = 1, /* invert powerpc-specific code transformation */ + CHECK = 0, /* check precise bounds in Squeeze array (otherwise checksum detects error) */ +}; + +static ulong chksum; +static int rdtab(Block*, Squeeze*, int); +static ulong* unsqueeze(ulong*, uchar*, uchar*, Squeeze*, Squeeze*, ulong); +static uchar* unsqzseg(uchar*, Block*, long, long, char*); +static Alarm* unsqzal; + +int +issqueezed(uchar *b) +{ + return GET4(b) == SQMAGIC? GET4(b+SQHDRLEN): 0; +} + +static void +unsqzdot(Alarm*) +{ + unsqzal = alarm(500, unsqzdot, nil); + print("."); +} + +long +unsqueezef(Block *b, ulong *entryp) +{ + uchar *loada, *wp; + ulong toptxt, topdat, oldsum; + long asis, nst, nsd; + Sqhdr *sqh; + Exec *ex; + + if(BLEN(b) < SQHDRLEN+EXECHDRLEN) + return -1; + sqh = (Sqhdr*)b->rp; + if(GET4(sqh->magic) != SQMAGIC) + return -1; + chksum = 0; + toptxt = GET4(sqh->toptxt); + topdat = GET4(sqh->topdat); + oldsum = GET4(sqh->sum); + asis = GET4(sqh->asis); + nst = GET4(sqh->text); + nsd = GET4(sqh->data); + b->rp += SQHDRLEN; + ex = (Exec*)b->rp; + if(GET4(ex->magic) != Q_MAGIC){ + print("zqs: not powerPC executable\n"); + return -1; + } + *entryp = GET4(ex->entry); + b->rp += EXECHDRLEN; + loada = KADDR(PADDR(*entryp)); + wp = unsqzseg(loada, b, nst, toptxt, "text"); + if(wp == nil){ + print("zqs: format error\n"); + return -1; + } + if(nsd){ + wp = (uchar*)PGROUND((ulong)wp); + wp = unsqzseg(wp, b, nsd, topdat, "data"); + if(wp == nil){ + print("zqs: format error\n"); + return -1; + } + } + if(asis){ + memmove(wp, b->rp, asis); + wp += asis; + b->rp += asis; + } + if(chksum != oldsum){ + print("\nsqueezed kernel: checksum error: %8.8lux need %8.8lux\n", chksum, oldsum); + return -1; + } + return wp-loada; +} + +static uchar * +unsqzseg(uchar *wp, Block *b, long ns, long top, char *what) +{ + static Squeeze sq3, sq4; + + print("unpack %s %8.8lux %lud:", what, wp, ns); + if(ns == 0) + return wp; + if(rdtab(b, &sq3, 0) < 0) + return nil; + if(rdtab(b, &sq4, 8) < 0) + return nil; + if(BLEN(b) < ns){ + print(" **size error\n"); + return nil; + } + unsqzal = alarm(500, unsqzdot, nil); + wp = (uchar*)unsqueeze((ulong*)wp, b->rp, b->rp+ns, &sq3, &sq4, top); + cancel(unsqzal); + unsqzal = nil; + print("\n"); + if(wp == nil){ + print("zqs: corrupt squeezed data stream\n"); + return nil; + } + b->rp += ns; + return wp; +} + +static ulong* +unsqueeze(ulong *wp, uchar *rp, uchar *ep, Squeeze *sq3, Squeeze *sq4, ulong top) +{ + ulong nx, csum; + int code, n; + + if(QFLAG){ + QREMAP(top); /* adjust top just once, outside the loop */ + } + csum = chksum; + while(rp < ep){ + /* no function calls within this loop for speed */ + code = *rp; + rp++; + n = 0; + nx = code>>4; + do{ + if(nx == 0){ + nx = top; + }else{ + if(nx==1){ + nx = (((((rp[3]<<8)|rp[2])<<8)|rp[1])<<8)|rp[0]; + rp += 4; + }else if(nx <= 8){ /* 2 to 8 */ + nx = ((nx-2)<<8) | rp[0]; + if(CHECK && nx >= sq4->n) + return nil; /* corrupted file */ + nx = sq4->tab[nx] | rp[1]; + rp += 2; + }else{ /* 9 to 15 */ + nx = ((nx-9)<<8) | rp[0]; + if(CHECK && nx >= sq3->n) + return nil; /* corrupted file */ + nx = sq3->tab[nx]; + rp++; + } + if(rp > ep) + return nil; /* corrupted file */ + if(QFLAG){ + QREMAP(nx); + } + } + *wp = nx; + wp++; + csum += nx; + nx = code & 0xF; + }while(++n == 1); + } + chksum = csum; + return wp; +} + +static int +rdtab(Block *b, Squeeze *sq, int shift) +{ + uchar *p, *ep; + ulong v, w; + int i; + + if(BLEN(b) < 2) + return -1; + i = (b->rp[0]<<8) | b->rp[1]; + if(1) + print(" T%d", i); + b->rp += 2; + if((i -= 2) > 0){ + if(BLEN(b) < i) + return -1; + } + sq->n = 0; + p = b->rp; + ep = b->rp+i; + b->rp += i; + v = 0; + while(p < ep){ + w = 0; + do{ + if(p >= ep) + return -1; + w = (w<<7) | (*p & 0x7F); + }while(*p++ & 0x80); + v += w; + if(0) + print("%d %8.8lux %8.8lux\n", sq->n, v, w); + sq->tab[sq->n++] = v<<shift; + } + return 0; +} |
