#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; intissqueezed(uchar *b){ return GET4(b) == SQMAGIC? GET4(b+SQHDRLEN): 0;} static voidunsqzdot(Alarm*){ unsqzal = alarm(500, unsqzdot, nil); print(".");} longunsqueezef(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 intrdtab(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;}
#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;
}