diff options
| author | Charles.Forsyth <devnull@localhost> | 2006-12-22 21:39:35 +0000 |
|---|---|---|
| committer | Charles.Forsyth <devnull@localhost> | 2006-12-22 21:39:35 +0000 |
| commit | 74a4d8c26dd3c1e9febcb717cfd6cb6512991a7a (patch) | |
| tree | c6e220ba61db3a6ea4052e6841296d829654e664 /os/boot/mpc/zqs.c | |
| parent | 46439007cf417cbd9ac8049bb4122c890097a0fa (diff) | |
20060303
Diffstat (limited to 'os/boot/mpc/zqs.c')
| -rw-r--r-- | os/boot/mpc/zqs.c | 234 |
1 files changed, 234 insertions, 0 deletions
diff --git a/os/boot/mpc/zqs.c b/os/boot/mpc/zqs.c new file mode 100644 index 00000000..b6296786 --- /dev/null +++ b/os/boot/mpc/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; +} |
