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