xref: /inferno-os/os/boot/puma/zqs.c (revision 74a4d8c26dd3c1e9febcb717cfd6cb6512991a7a)
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