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