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