xref: /plan9-contrib/sys/src/boot/vt4/boot.c (revision da917039c7f233c1a27d212bf012c6afa758af39)
1 #include "include.h"
2 #include "ip.h"
3 #include "/sys/src/libmach/elf.h"
4 
5 int	tftpupload(char *name, void *p, int len);
6 
7 extern ulong cpuentry;
8 
9 static uchar elfident[7] = {
10 	'\177', 'E', 'L', 'F', '\1', '\1', '\1'
11 };
12 static Ehdr ehdr, rehdr;
13 static Phdr *phdr;
14 static int curphdr;
15 static ulong curoff;
16 static ulong elftotal;
17 
18 static long (*swal)(long);
19 static ushort (*swab)(ushort);
20 
21 /*
22  * big-endian short
23  */
24 ushort
beswab(ushort s)25 beswab(ushort s)
26 {
27 	uchar *p;
28 
29 	p = (uchar*)&s;
30 	return (p[0]<<8) | p[1];
31 }
32 
33 /*
34  * big-endian long
35  */
36 long
beswal(long l)37 beswal(long l)
38 {
39 	uchar *p;
40 
41 	p = (uchar*)&l;
42 	return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3];
43 }
44 
45 /*
46  * little-endian short
47  */
48 ushort
leswab(ushort s)49 leswab(ushort s)
50 {
51 	uchar *p;
52 
53 	p = (uchar*)&s;
54 	return (p[1]<<8) | p[0];
55 }
56 
57 /*
58  * little-endian long
59  */
60 long
leswal(long l)61 leswal(long l)
62 {
63 	uchar *p;
64 
65 	p = (uchar*)&l;
66 	return (p[3]<<24) | (p[2]<<16) | (p[1]<<8) | p[0];
67 }
68 
69 /*
70  * Convert header to canonical form
71  */
72 static void
hswal(long * lp,int n,long (* swap)(long))73 hswal(long *lp, int n, long (*swap) (long))
74 {
75 	while (n--) {
76 		*lp = (*swap) (*lp);
77 		lp++;
78 	}
79 }
80 
81 static int
readehdr(Boot * b)82 readehdr(Boot *b)
83 {
84 	int i;
85 
86 	/* bitswap the header according to the DATA format */
87 	if(ehdr.ident[CLASS] != ELFCLASS32) {
88 		print("bad ELF class - not 32 bit\n");
89 		return 0;
90 	}
91 	if(ehdr.ident[DATA] == ELFDATA2LSB) {
92 		swab = leswab;
93 		swal = leswal;
94 	} else if(ehdr.ident[DATA] == ELFDATA2MSB) {
95 		swab = beswab;
96 		swal = beswal;
97 	} else {
98 		print("bad ELF encoding - not big or little endian\n");
99 		return 0;
100 	}
101 	memmove(&rehdr, &ehdr, sizeof(Ehdr));
102 
103 	ehdr.type = swab(ehdr.type);
104 	ehdr.machine = swab(ehdr.machine);
105 	ehdr.version = swal(ehdr.version);
106 	ehdr.elfentry = swal(ehdr.elfentry);
107 	ehdr.phoff = swal(ehdr.phoff);
108 	ehdr.shoff = swal(ehdr.shoff);
109 	ehdr.flags = swal(ehdr.flags);
110 	ehdr.ehsize = swab(ehdr.ehsize);
111 	ehdr.phentsize = swab(ehdr.phentsize);
112 	ehdr.phnum = swab(ehdr.phnum);
113 	ehdr.shentsize = swab(ehdr.shentsize);
114 	ehdr.shnum = swab(ehdr.shnum);
115 	ehdr.shstrndx = swab(ehdr.shstrndx);
116 	if(ehdr.type != EXEC || ehdr.version != CURRENT)
117 		return 0;
118 	if(ehdr.phentsize != sizeof(Phdr))
119 		return 0;
120 
121 	if(debug)
122 		print("readehdr OK entry 0x%lux\n", ehdr.elfentry);
123 
124 	curoff = sizeof(Ehdr);
125 	i = ehdr.phoff+ehdr.phentsize*ehdr.phnum - curoff;
126 	b->state = READPHDR;
127 	b->bp = (char*)malloc(i);
128 	b->wp = b->bp;
129 	b->ep = b->wp + i;
130 	phdr = (Phdr*)(b->bp + ehdr.phoff-sizeof(Ehdr));
131 	if(debug)
132 		print("phdr...");
133 
134 	return 1;
135 }
136 
137 static int
nextphdr(Boot * b)138 nextphdr(Boot *b)
139 {
140 	Phdr *php;
141 	ulong entry, offset;
142 	char *paddr;
143 
144 	if(debug)
145 		print("readedata %d\n", curphdr);
146 
147 	for(; curphdr < ehdr.phnum; curphdr++){
148 		php = phdr+curphdr;
149 		if(php->type != LOAD)
150 			continue;
151 		offset = php->offset;
152 		paddr = (char*)PADDR(php->paddr);
153 		if(offset < curoff){
154 			/*
155 			 * Can't (be bothered to) rewind the
156 			 * input, it might be from tftp. If we
157 			 * did then we could boot FreeBSD kernels
158 			 * too maybe.
159 			 */
160 			return 0;
161 		}
162 		if(php->offset > curoff){
163 			b->state = READEPAD;
164 			b->bp = (char*)malloc(offset - curoff);
165 			b->wp = b->bp;
166 			b->ep = b->wp + offset - curoff;
167 			if(debug)
168 				print("nextphdr %lud...\n", offset - curoff);
169 			return 1;
170 		}
171 		b->state = READEDATA;
172 		b->bp = paddr;
173 		b->wp = b->bp;
174 		b->ep = b->wp+php->filesz;
175 		print("%ud+", php->filesz);
176 		elftotal += php->filesz;
177 		if(debug)
178 			print("nextphdr %ud@0x%p\n", php->filesz, paddr);
179 
180 		return 1;
181 	}
182 
183 	if(curphdr != 0){
184 		print("=%lud\n", elftotal);
185 		b->state = TRYBOOT;
186 		entry = ehdr.elfentry & ~0xF0000000;
187 		PLLONG(b->exec.entry, entry);
188 		return 1;
189 	}
190 
191 	return 0;
192 }
193 
194 static int
readepad(Boot * b)195 readepad(Boot *b)
196 {
197 	Phdr *php;
198 
199 	php = phdr+curphdr;
200 	if(debug)
201 		print("readepad %d\n", curphdr);
202 	curoff = php->offset;
203 
204 	return nextphdr(b);
205 }
206 
207 static int
readedata(Boot * b)208 readedata(Boot *b)
209 {
210 	Phdr *php;
211 
212 	php = phdr+curphdr;
213 	if(debug)
214 		print("readedata %d\n", curphdr);
215 	if(php->filesz < php->memsz){
216 		print("%lud",  php->memsz-php->filesz);
217 		elftotal += php->memsz-php->filesz;
218 		memset((char*)(PADDR(php->paddr)+php->filesz), 0, php->memsz-php->filesz);
219 	}
220 	curoff = php->offset+php->filesz;
221 	curphdr++;
222 
223 	return nextphdr(b);
224 }
225 
226 static int
readphdr(Boot * b)227 readphdr(Boot *b)
228 {
229 	Phdr *php;
230 
231 	php = phdr;
232 	hswal((long*)php, ehdr.phentsize*ehdr.phnum/sizeof(long), swal);
233 	if(debug)
234 		print("phdr curoff %lud vaddr 0x%lux paddr 0x%lux\n",
235 			curoff, php->vaddr, php->paddr);
236 
237 	curoff = ehdr.phoff+ehdr.phentsize*ehdr.phnum;
238 	curphdr = 0;
239 
240 	return nextphdr(b);
241 }
242 
243 static ulong chksum, length;
244 
245 static void
sum(void * vp,int len)246 sum(void *vp, int len)
247 {
248 	unsigned long *p;
249 
250 	if (len % sizeof(int) != 0) {
251 		print("sum: len %d not a multiple of word size\n",
252 			len);
253 		return;
254 	}
255 	p = vp;
256 	len /= sizeof *p;
257 	while (len-- > 0)
258 		chksum += *p++;
259 }
260 
261 static int
addbytes(char ** dbuf,char * edbuf,char ** sbuf,char * esbuf)262 addbytes(char **dbuf, char *edbuf, char **sbuf, char *esbuf)
263 {
264 	int n;
265 	static ulong *start;
266 
267 	n = edbuf - *dbuf;
268 	if(n <= 0)
269 		return 0;
270 	if(n > esbuf - *sbuf)
271 		n = esbuf - *sbuf;
272 	if(n <= 0)
273 		return -1;
274 
275 	memmove(*dbuf, *sbuf, n);
276 	coherence();
277 
278 	/* verify that the copy worked */
279 	if (memcmp(*dbuf, *sbuf, n) != 0)
280 		panic("addbytes: memmove copied %d bytes wrong from %#p to %#p",
281 			n, *sbuf, *dbuf);
282 	*sbuf += n;
283 	*dbuf += n;
284 	return edbuf - *dbuf;
285 }
286 
287 int
bootpass(Boot * b,void * vbuf,int nbuf)288 bootpass(Boot *b, void *vbuf, int nbuf)
289 {
290 	char *buf, *ebuf;
291 	Exec *ep;
292 	ulong entry, data, text, bss;
293 
294 	SET(text, data);
295 	USED(text, data);
296 	if(b->state == FAILED)
297 		return FAIL;
298 
299 	if(nbuf == 0)
300 		goto Endofinput;
301 
302 	buf = vbuf;
303 	ebuf = buf+nbuf;
304 	while(addbytes(&b->wp, b->ep, &buf, ebuf) == 0) {
305 		switch(b->state) {
306 		case INITKERNEL:
307 			b->state = READEXEC;
308 			b->bp = (char*)&b->exec;
309 			b->wp = b->bp;
310 			b->ep = b->bp+sizeof(Exec);
311 			break;
312 		case READEXEC:
313 			ep = &b->exec;
314 			if(GLLONG(ep->magic) == Q_MAGIC) {
315 				b->state = READ9TEXT;
316 				b->bp = (char*)PADDR(GLLONG(ep->entry));
317 				b->wp = b->bp;
318 				b->ep = b->wp+GLLONG(ep->text);
319 				print("%lud", GLLONG(ep->text));
320 				break;
321 			}
322 
323 			/*
324 			 * Check for ELF.
325 			 */
326 			if(memcmp(b->bp, elfident, 4) == 0){
327 				b->state = READEHDR;
328 				b->bp = (char*)&ehdr;
329 				b->wp = b->bp;
330 				b->ep = b->wp + sizeof(Ehdr);
331 				memmove(b->bp, &b->exec, sizeof(Exec));
332 				b->wp += sizeof(Exec);
333 				print("elf...");
334 				break;
335 			}
336 
337 			print("bad kernel format\n");
338 			b->state = FAILED;
339 			return FAIL;
340 
341 		case READ9TEXT:
342 			ep = &b->exec;
343 			b->state = READ9DATA;
344 			b->bp = (char*)UTROUND(PADDR(GLLONG(ep->entry)) +
345 				GLLONG(ep->text));
346 			b->wp = b->bp;
347 			b->ep = b->wp + GLLONG(ep->data);
348 			{
349 				/*
350 				 * fill the gap between text and first page
351 				 * of data.
352 				 */
353 				int wds;
354 				ulong *dst = (ulong *)(PADDR(GLLONG(ep->entry))+
355 					GLLONG(ep->text));
356 
357 				for (wds = (ulong *)b->bp - dst; wds-- > 0;
358 				    dst++)
359 					*dst = (uintptr)dst;
360 			}
361 			print("+%ld", GLLONG(ep->data));
362 			length = b->ep - (char *)PADDR(GLLONG(ep->entry));
363 			break;
364 
365 		case READ9DATA:
366 			ep = &b->exec;
367 			bss = GLLONG(ep->bss);
368 			print("+%ld=%ld\n",
369 				bss, GLLONG(ep->text)+GLLONG(ep->data)+bss);
370 			b->state = TRYBOOT;
371 			return ENOUGH;
372 
373 		case READEHDR:
374 			if(!readehdr(b)){
375 				print("readehdr failed\n");
376 				b->state = FAILED;
377 				return FAIL;
378 			}
379 			break;
380 
381 		case READPHDR:
382 			if(!readphdr(b)){
383 				b->state = FAILED;
384 				return FAIL;
385 			}
386 			break;
387 
388 		case READEPAD:
389 			if(!readepad(b)){
390 				b->state = FAILED;
391 				return FAIL;
392 			}
393 			break;
394 
395 		case READEDATA:
396 			if(!readedata(b)){
397 				b->state = FAILED;
398 				return FAIL;
399 			}
400 			if(b->state == TRYBOOT)
401 				return ENOUGH;
402 			break;
403 
404 		case TRYBOOT:
405 		case READGZIP:
406 			return ENOUGH;
407 
408 		case READ9LOAD:
409 		case INIT9LOAD:
410 			panic("9load");
411 
412 		default:
413 			panic("bootstate");
414 		}
415 	}
416 	return MORE;
417 
418 
419 Endofinput:
420 	/* end of input */
421 	switch(b->state) {
422 	case INITKERNEL:
423 	case READEXEC:
424 	case READ9TEXT:
425 	case READ9DATA:
426 	case READEHDR:
427 	case READPHDR:
428 	case READEPAD:
429 	case READEDATA:
430 		print("premature EOF\n");
431 		b->state = FAILED;
432 		return FAIL;
433 
434 	case TRYBOOT:
435 		delay(100);
436 		syncall();
437 		entry = GLLONG(b->exec.entry);
438 		dcflush(PADDR(entry), 4*1024*1024);		/* HACK */
439 
440 		sum((void *)PADDR(entry), length);
441 		print("checksum: %#luX (on length %lud)\n", chksum, length);
442 
443 		print("entry: 0x%lux\n", entry);
444 		delay(20);
445 
446 		cpuentry = entry;		/* for second cpu's use */
447 		coherence();
448 		dcflush((uintptr)&cpuentry, sizeof cpuentry);
449 
450 		warp9(PADDR(entry));
451 
452 		b->state = FAILED;
453 		return FAIL;
454 
455 	case INIT9LOAD:
456 	case READ9LOAD:
457 		panic("end 9load");
458 
459 	default:
460 		panic("bootdone");
461 	}
462 	b->state = FAILED;
463 	return FAIL;
464 }
465