1*74a4d8c2SCharles.Forsyth #include "boot.h"
2*74a4d8c2SCharles.Forsyth #include "squeeze.h"
3*74a4d8c2SCharles.Forsyth
4*74a4d8c2SCharles.Forsyth #define EXECHDRLEN (8*4)
5*74a4d8c2SCharles.Forsyth
6*74a4d8c2SCharles.Forsyth typedef struct Squeeze Squeeze;
7*74a4d8c2SCharles.Forsyth struct Squeeze {
8*74a4d8c2SCharles.Forsyth int n;
9*74a4d8c2SCharles.Forsyth ulong tab[7*256];
10*74a4d8c2SCharles.Forsyth };
11*74a4d8c2SCharles.Forsyth
12*74a4d8c2SCharles.Forsyth #define GET4(p) (((((((p)[0]<<8)|(p)[1])<<8)|(p)[2])<<8)|(p)[3])
13*74a4d8c2SCharles.Forsyth
14*74a4d8c2SCharles.Forsyth /*
15*74a4d8c2SCharles.Forsyth * for speed of unsqueezing from Flash, certain checks are
16*74a4d8c2SCharles.Forsyth * not done inside the loop (as they would be in the unsqueeze program zqs),
17*74a4d8c2SCharles.Forsyth * but instead the checksum is expected to catch corrupted files.
18*74a4d8c2SCharles.Forsyth * in fact the Squeeze array bounds can't be exceeded in practice
19*74a4d8c2SCharles.Forsyth * because the tables are always full for a squeezed kernel.
20*74a4d8c2SCharles.Forsyth */
21*74a4d8c2SCharles.Forsyth enum {
22*74a4d8c2SCharles.Forsyth QFLAG = 1, /* invert powerpc-specific code transformation */
23*74a4d8c2SCharles.Forsyth CHECK = 0, /* check precise bounds in Squeeze array (otherwise checksum detects error) */
24*74a4d8c2SCharles.Forsyth };
25*74a4d8c2SCharles.Forsyth
26*74a4d8c2SCharles.Forsyth static ulong chksum;
27*74a4d8c2SCharles.Forsyth static int rdtab(Block*, Squeeze*, int);
28*74a4d8c2SCharles.Forsyth static ulong* unsqueeze(ulong*, uchar*, uchar*, Squeeze*, Squeeze*, ulong);
29*74a4d8c2SCharles.Forsyth static uchar* unsqzseg(uchar*, Block*, long, long, char*);
30*74a4d8c2SCharles.Forsyth static Alarm* unsqzal;
31*74a4d8c2SCharles.Forsyth
32*74a4d8c2SCharles.Forsyth int
issqueezed(uchar * b)33*74a4d8c2SCharles.Forsyth issqueezed(uchar *b)
34*74a4d8c2SCharles.Forsyth {
35*74a4d8c2SCharles.Forsyth return GET4(b) == SQMAGIC? GET4(b+SQHDRLEN): 0;
36*74a4d8c2SCharles.Forsyth }
37*74a4d8c2SCharles.Forsyth
38*74a4d8c2SCharles.Forsyth static void
unsqzdot(void *)39*74a4d8c2SCharles.Forsyth unsqzdot(void*)
40*74a4d8c2SCharles.Forsyth {
41*74a4d8c2SCharles.Forsyth unsqzal = alarm(500, unsqzdot, nil);
42*74a4d8c2SCharles.Forsyth print(".");
43*74a4d8c2SCharles.Forsyth }
44*74a4d8c2SCharles.Forsyth
45*74a4d8c2SCharles.Forsyth long
unsqueezef(Block * b,ulong * entryp)46*74a4d8c2SCharles.Forsyth unsqueezef(Block *b, ulong *entryp)
47*74a4d8c2SCharles.Forsyth {
48*74a4d8c2SCharles.Forsyth uchar *loada, *wp;
49*74a4d8c2SCharles.Forsyth ulong toptxt, topdat, oldsum;
50*74a4d8c2SCharles.Forsyth long asis, nst, nsd;
51*74a4d8c2SCharles.Forsyth Sqhdr *sqh;
52*74a4d8c2SCharles.Forsyth Exec *ex;
53*74a4d8c2SCharles.Forsyth
54*74a4d8c2SCharles.Forsyth if(BLEN(b) < SQHDRLEN+EXECHDRLEN)
55*74a4d8c2SCharles.Forsyth return -1;
56*74a4d8c2SCharles.Forsyth sqh = (Sqhdr*)b->rp;
57*74a4d8c2SCharles.Forsyth if(GET4(sqh->magic) != SQMAGIC)
58*74a4d8c2SCharles.Forsyth return -1;
59*74a4d8c2SCharles.Forsyth chksum = 0;
60*74a4d8c2SCharles.Forsyth toptxt = GET4(sqh->toptxt);
61*74a4d8c2SCharles.Forsyth topdat = GET4(sqh->topdat);
62*74a4d8c2SCharles.Forsyth oldsum = GET4(sqh->sum);
63*74a4d8c2SCharles.Forsyth asis = GET4(sqh->asis);
64*74a4d8c2SCharles.Forsyth nst = GET4(sqh->text);
65*74a4d8c2SCharles.Forsyth nsd = GET4(sqh->data);
66*74a4d8c2SCharles.Forsyth b->rp += SQHDRLEN;
67*74a4d8c2SCharles.Forsyth ex = (Exec*)b->rp;
68*74a4d8c2SCharles.Forsyth if(GET4(ex->magic) != E_MAGIC){
69*74a4d8c2SCharles.Forsyth print("zqs: not StrongARM executable\n");
70*74a4d8c2SCharles.Forsyth return -1;
71*74a4d8c2SCharles.Forsyth }
72*74a4d8c2SCharles.Forsyth *entryp = GET4(ex->entry);
73*74a4d8c2SCharles.Forsyth b->rp += EXECHDRLEN;
74*74a4d8c2SCharles.Forsyth loada = KADDR(PADDR(*entryp));
75*74a4d8c2SCharles.Forsyth wp = unsqzseg(loada, b, nst, toptxt, "text");
76*74a4d8c2SCharles.Forsyth if(wp == nil){
77*74a4d8c2SCharles.Forsyth print("zqs: format error\n");
78*74a4d8c2SCharles.Forsyth return -1;
79*74a4d8c2SCharles.Forsyth }
80*74a4d8c2SCharles.Forsyth if(nsd){
81*74a4d8c2SCharles.Forsyth wp = (uchar*)PGROUND((ulong)wp);
82*74a4d8c2SCharles.Forsyth wp = unsqzseg(wp, b, nsd, topdat, "data");
83*74a4d8c2SCharles.Forsyth if(wp == nil){
84*74a4d8c2SCharles.Forsyth print("zqs: format error\n");
85*74a4d8c2SCharles.Forsyth return -1;
86*74a4d8c2SCharles.Forsyth }
87*74a4d8c2SCharles.Forsyth }
88*74a4d8c2SCharles.Forsyth if(asis){
89*74a4d8c2SCharles.Forsyth memmove(wp, b->rp, asis);
90*74a4d8c2SCharles.Forsyth wp += asis;
91*74a4d8c2SCharles.Forsyth b->rp += asis;
92*74a4d8c2SCharles.Forsyth }
93*74a4d8c2SCharles.Forsyth if(chksum != oldsum){
94*74a4d8c2SCharles.Forsyth print("\nsqueezed kernel: checksum error: %8.8lux need %8.8lux\n", chksum, oldsum);
95*74a4d8c2SCharles.Forsyth return -1;
96*74a4d8c2SCharles.Forsyth }
97*74a4d8c2SCharles.Forsyth return wp-loada;
98*74a4d8c2SCharles.Forsyth }
99*74a4d8c2SCharles.Forsyth
100*74a4d8c2SCharles.Forsyth static uchar *
unsqzseg(uchar * wp,Block * b,long ns,long top,char * what)101*74a4d8c2SCharles.Forsyth unsqzseg(uchar *wp, Block *b, long ns, long top, char *what)
102*74a4d8c2SCharles.Forsyth {
103*74a4d8c2SCharles.Forsyth static Squeeze sq3, sq4;
104*74a4d8c2SCharles.Forsyth
105*74a4d8c2SCharles.Forsyth print("unpack %s %8.8lux %lud:", what, wp, ns);
106*74a4d8c2SCharles.Forsyth if(ns == 0)
107*74a4d8c2SCharles.Forsyth return wp;
108*74a4d8c2SCharles.Forsyth if(rdtab(b, &sq3, 0) < 0)
109*74a4d8c2SCharles.Forsyth return nil;
110*74a4d8c2SCharles.Forsyth if(rdtab(b, &sq4, 8) < 0)
111*74a4d8c2SCharles.Forsyth return nil;
112*74a4d8c2SCharles.Forsyth if(BLEN(b) < ns){
113*74a4d8c2SCharles.Forsyth print(" **size error\n");
114*74a4d8c2SCharles.Forsyth return nil;
115*74a4d8c2SCharles.Forsyth }
116*74a4d8c2SCharles.Forsyth unsqzal = alarm(500, unsqzdot, nil);
117*74a4d8c2SCharles.Forsyth wp = (uchar*)unsqueeze((ulong*)wp, b->rp, b->rp+ns, &sq3, &sq4, top);
118*74a4d8c2SCharles.Forsyth cancel(unsqzal);
119*74a4d8c2SCharles.Forsyth unsqzal = nil;
120*74a4d8c2SCharles.Forsyth print("\n");
121*74a4d8c2SCharles.Forsyth if(wp == nil){
122*74a4d8c2SCharles.Forsyth print("zqs: corrupt squeezed data stream\n");
123*74a4d8c2SCharles.Forsyth return nil;
124*74a4d8c2SCharles.Forsyth }
125*74a4d8c2SCharles.Forsyth b->rp += ns;
126*74a4d8c2SCharles.Forsyth return wp;
127*74a4d8c2SCharles.Forsyth }
128*74a4d8c2SCharles.Forsyth
129*74a4d8c2SCharles.Forsyth static ulong*
unsqueeze(ulong * wp,uchar * rp,uchar * ep,Squeeze * sq3,Squeeze * sq4,ulong top)130*74a4d8c2SCharles.Forsyth unsqueeze(ulong *wp, uchar *rp, uchar *ep, Squeeze *sq3, Squeeze *sq4, ulong top)
131*74a4d8c2SCharles.Forsyth {
132*74a4d8c2SCharles.Forsyth ulong nx, csum;
133*74a4d8c2SCharles.Forsyth int code, n;
134*74a4d8c2SCharles.Forsyth
135*74a4d8c2SCharles.Forsyth if(QFLAG){
136*74a4d8c2SCharles.Forsyth QREMAP(top); /* adjust top just once, outside the loop */
137*74a4d8c2SCharles.Forsyth }
138*74a4d8c2SCharles.Forsyth csum = chksum;
139*74a4d8c2SCharles.Forsyth while(rp < ep){
140*74a4d8c2SCharles.Forsyth /* no function calls within this loop for speed */
141*74a4d8c2SCharles.Forsyth code = *rp;
142*74a4d8c2SCharles.Forsyth rp++;
143*74a4d8c2SCharles.Forsyth n = 0;
144*74a4d8c2SCharles.Forsyth nx = code>>4;
145*74a4d8c2SCharles.Forsyth do{
146*74a4d8c2SCharles.Forsyth if(nx == 0){
147*74a4d8c2SCharles.Forsyth nx = top;
148*74a4d8c2SCharles.Forsyth }else{
149*74a4d8c2SCharles.Forsyth if(nx==1){
150*74a4d8c2SCharles.Forsyth nx = (((((rp[3]<<8)|rp[2])<<8)|rp[1])<<8)|rp[0];
151*74a4d8c2SCharles.Forsyth rp += 4;
152*74a4d8c2SCharles.Forsyth }else if(nx <= 8){ /* 2 to 8 */
153*74a4d8c2SCharles.Forsyth nx = ((nx-2)<<8) | rp[0];
154*74a4d8c2SCharles.Forsyth if(CHECK && nx >= sq4->n)
155*74a4d8c2SCharles.Forsyth return nil; /* corrupted file */
156*74a4d8c2SCharles.Forsyth nx = sq4->tab[nx] | rp[1];
157*74a4d8c2SCharles.Forsyth rp += 2;
158*74a4d8c2SCharles.Forsyth }else{ /* 9 to 15 */
159*74a4d8c2SCharles.Forsyth nx = ((nx-9)<<8) | rp[0];
160*74a4d8c2SCharles.Forsyth if(CHECK && nx >= sq3->n)
161*74a4d8c2SCharles.Forsyth return nil; /* corrupted file */
162*74a4d8c2SCharles.Forsyth nx = sq3->tab[nx];
163*74a4d8c2SCharles.Forsyth rp++;
164*74a4d8c2SCharles.Forsyth }
165*74a4d8c2SCharles.Forsyth if(rp > ep)
166*74a4d8c2SCharles.Forsyth return nil; /* corrupted file */
167*74a4d8c2SCharles.Forsyth if(QFLAG){
168*74a4d8c2SCharles.Forsyth QREMAP(nx);
169*74a4d8c2SCharles.Forsyth }
170*74a4d8c2SCharles.Forsyth }
171*74a4d8c2SCharles.Forsyth *wp = nx;
172*74a4d8c2SCharles.Forsyth wp++;
173*74a4d8c2SCharles.Forsyth csum += nx;
174*74a4d8c2SCharles.Forsyth nx = code & 0xF;
175*74a4d8c2SCharles.Forsyth }while(++n == 1);
176*74a4d8c2SCharles.Forsyth }
177*74a4d8c2SCharles.Forsyth chksum = csum;
178*74a4d8c2SCharles.Forsyth return wp;
179*74a4d8c2SCharles.Forsyth }
180*74a4d8c2SCharles.Forsyth
181*74a4d8c2SCharles.Forsyth static int
rdtab(Block * b,Squeeze * sq,int shift)182*74a4d8c2SCharles.Forsyth rdtab(Block *b, Squeeze *sq, int shift)
183*74a4d8c2SCharles.Forsyth {
184*74a4d8c2SCharles.Forsyth uchar *p, *ep;
185*74a4d8c2SCharles.Forsyth ulong v, w;
186*74a4d8c2SCharles.Forsyth int i;
187*74a4d8c2SCharles.Forsyth
188*74a4d8c2SCharles.Forsyth if(BLEN(b) < 2)
189*74a4d8c2SCharles.Forsyth return -1;
190*74a4d8c2SCharles.Forsyth i = (b->rp[0]<<8) | b->rp[1];
191*74a4d8c2SCharles.Forsyth if(1)
192*74a4d8c2SCharles.Forsyth print(" T%d", i);
193*74a4d8c2SCharles.Forsyth b->rp += 2;
194*74a4d8c2SCharles.Forsyth if((i -= 2) > 0){
195*74a4d8c2SCharles.Forsyth if(BLEN(b) < i)
196*74a4d8c2SCharles.Forsyth return -1;
197*74a4d8c2SCharles.Forsyth }
198*74a4d8c2SCharles.Forsyth sq->n = 0;
199*74a4d8c2SCharles.Forsyth p = b->rp;
200*74a4d8c2SCharles.Forsyth ep = b->rp+i;
201*74a4d8c2SCharles.Forsyth b->rp += i;
202*74a4d8c2SCharles.Forsyth v = 0;
203*74a4d8c2SCharles.Forsyth while(p < ep){
204*74a4d8c2SCharles.Forsyth w = 0;
205*74a4d8c2SCharles.Forsyth do{
206*74a4d8c2SCharles.Forsyth if(p >= ep)
207*74a4d8c2SCharles.Forsyth return -1;
208*74a4d8c2SCharles.Forsyth w = (w<<7) | (*p & 0x7F);
209*74a4d8c2SCharles.Forsyth }while(*p++ & 0x80);
210*74a4d8c2SCharles.Forsyth v += w;
211*74a4d8c2SCharles.Forsyth if(0)
212*74a4d8c2SCharles.Forsyth print("%d %8.8lux %8.8lux\n", sq->n, v, w);
213*74a4d8c2SCharles.Forsyth sq->tab[sq->n++] = v<<shift;
214*74a4d8c2SCharles.Forsyth }
215*74a4d8c2SCharles.Forsyth return 0;
216*74a4d8c2SCharles.Forsyth }
217