Merge from Etherboot 5.4
[people/dverkamp/gpxe.git] / src / core / elf_loader.c
1 #include "elf.h"
2
3 #ifndef ELF_CHECK_ARCH
4 #error ELF_CHECK_ARCH not defined
5 #endif
6
7 #define ELF_NOTES 1
8 #define ELF_DEBUG 0
9
10 struct elf_state
11 {
12         union {
13                 Elf32_Ehdr elf32;
14                 Elf64_Ehdr elf64;
15         } e;
16         union {
17                 Elf32_Phdr phdr32[1];
18                 Elf64_Phdr phdr64[1];
19                 unsigned char dummy[1024];
20         } p;
21         unsigned long curaddr;
22         int segment;            /* current segment number, -1 for none */
23         uint64_t loc;           /* start offset of current block */
24         uint64_t skip;          /* padding to be skipped to current segment */
25         unsigned long toread;   /* remaining data to be read in the segment */
26 #if ELF_NOTES
27         int check_ip_checksum;
28         uint16_t ip_checksum;
29         unsigned long ip_checksum_offset;
30 #endif
31 };
32
33 static struct elf_state estate;
34
35 static unsigned long find_segment(unsigned long size, unsigned long align)
36 {
37         unsigned i;
38         /* Verify I have a power of 2 alignment */
39         if (align & (align - 1)) {
40                 return ULONG_MAX;
41         }
42         for(i = 0; i < meminfo.map_count; i++) {
43                 unsigned long r_start, r_end;
44                 if (meminfo.map[i].type != E820_RAM)
45                         continue;
46                 if ((meminfo.map[i].addr + meminfo.map[i].size) > ULONG_MAX) {
47                         continue;
48                 }
49                 r_start = meminfo.map[i].addr;
50                 r_end = r_start + meminfo.map[i].size;
51                 /* Don't allow the segment to overlap etherboot */
52                 if ((r_end > virt_to_phys(_text)) && (r_start < virt_to_phys(_text))) {
53                         r_end = virt_to_phys(_text);
54                 }
55                 if ((r_start > virt_to_phys(_text)) && (r_start < virt_to_phys(_end))) {
56                         r_start = virt_to_phys(_end);
57                 }
58                 /* Don't allow the segment to overlap the heap */
59                 if ((r_end > heap_ptr) && (r_start < heap_ptr)) {
60                         r_end = heap_ptr;
61                 }
62                 if ((r_start > heap_ptr) && (r_start < heap_bot)) {
63                         r_start = heap_ptr;
64                 }
65                 r_start = (r_start + align - 1) & ~(align - 1);
66                 if ((r_end >= r_start) && ((r_end - r_start) >= size)) {
67                         return r_start;
68                 }
69         }
70         /* I did not find anything :( */
71         return ULONG_MAX;
72 }
73
74 static void elf_boot(unsigned long machine, unsigned long entry)
75 {
76         int result;
77         struct Elf_Bhdr *hdr;
78         multiboot_boot(entry);
79         /* We cleanup unconditionally, and then reawaken the network
80          * adapter after the longjmp.
81          */
82         hdr = prepare_boot_params(&estate.e);
83         result = elf_start(machine, entry, virt_to_phys(hdr));
84         if (result == 0) {
85                 result = -1;
86         }
87         printf("Secondary program returned %d\n", result);
88         longjmp(restart_etherboot, result);
89 }
90
91 #if ELF_NOTES
92 static int elf_prep_segment(
93         unsigned long start __unused, unsigned long mid __unused, unsigned long end __unused,
94         unsigned long istart, unsigned long iend)
95
96 {
97         if (estate.check_ip_checksum) {
98                 if ((istart <= estate.ip_checksum_offset) && 
99                         (iend > estate.ip_checksum_offset)) {
100                         /* The checksum note is also loaded in a
101                          * PT_LOAD segment, so the computed checksum
102                          * should be 0.
103                          */
104                         estate.ip_checksum = 0;
105                 }
106         }
107         return 1;
108 }
109 #else
110 #define elf_prep_segment(start, mid, end, istart, iend) (1)
111 #endif
112
113
114 #if ELF_NOTES
115 static void process_elf_notes(unsigned char *header,
116         unsigned long offset, unsigned long length)
117 {
118         unsigned char *note, *end;
119         char *program, *version;
120
121         estate.check_ip_checksum = 0;
122         note = header + offset;
123         end = note + length;
124         program = version = 0;
125         while(note < end) {
126                 Elf_Nhdr *hdr;
127                 unsigned char *n_name, *n_desc, *next;
128                 hdr = (Elf_Nhdr *)note;
129                 n_name = note + sizeof(*hdr);
130                 n_desc = n_name + ((hdr->n_namesz + 3) & ~3);
131                 next = n_desc + ((hdr->n_descsz + 3) & ~3);
132                 if (next > end) {
133                         break;
134                 }
135                 if ((hdr->n_namesz == sizeof(ELF_NOTE_BOOT)) && 
136                         (memcmp(n_name, ELF_NOTE_BOOT, sizeof(ELF_NOTE_BOOT)) == 0)) {
137                         switch(hdr->n_type) {
138                         case EIN_PROGRAM_NAME:
139                                 if (n_desc[hdr->n_descsz -1] == 0) {
140                                         program = n_desc;
141                                 }
142                                 break;
143                         case EIN_PROGRAM_VERSION:
144                                 if (n_desc[hdr->n_descsz -1] == 0) {
145                                         version = n_desc;
146                                 }
147                                 break;
148                         case EIN_PROGRAM_CHECKSUM:
149                                 estate.check_ip_checksum = 1;
150                                 estate.ip_checksum = *((uint16_t *)n_desc);
151                                 /* Remember where the segment is so
152                                  * I can detect segment overlaps.
153                                  */
154                                 estate.ip_checksum_offset = n_desc - header;
155 #if ELF_DEBUG
156                                 printf("Checksum: %hx\n", estate.ip_checksum);
157 #endif
158
159                                 break;
160                         }
161                 }
162 #if ELF_DEBUG
163                 printf("n_type: %x n_name(%d): %s n_desc(%d): %s\n", 
164                         hdr->n_type,
165                         hdr->n_namesz, n_name,
166                         hdr->n_descsz, n_desc);
167 #endif
168                 note = next;
169         }
170         if (program && version) {
171                 printf("\nLoading %s version: %s\n", program, version);
172         }
173 }
174 #endif
175
176 #ifdef  ELF_IMAGE
177 static sector_t elf32_download(unsigned char *data, unsigned int len, int eof);
178 static inline os_download_t elf32_probe(unsigned char *data, unsigned int len)
179 {
180         unsigned long phdr_size;
181         if (len < sizeof(estate.e.elf32)) {
182                 return 0;
183         }
184         memcpy(&estate.e.elf32, data, sizeof(estate.e.elf32));
185         if ((estate.e.elf32.e_ident[EI_MAG0] != ELFMAG0) ||
186                 (estate.e.elf32.e_ident[EI_MAG1] != ELFMAG1) ||
187                 (estate.e.elf32.e_ident[EI_MAG2] != ELFMAG2) ||
188                 (estate.e.elf32.e_ident[EI_MAG3] != ELFMAG3) ||
189                 (estate.e.elf32.e_ident[EI_CLASS] != ELFCLASS32) ||
190                 (estate.e.elf32.e_ident[EI_DATA] != ELFDATA_CURRENT) ||
191                 (estate.e.elf32.e_ident[EI_VERSION] != EV_CURRENT) ||
192                 (       (estate.e.elf32.e_type != ET_EXEC) &&
193                         (estate.e.elf32.e_type != ET_DYN)) ||
194                 (estate.e.elf32.e_version != EV_CURRENT) ||
195                 (estate.e.elf32.e_ehsize != sizeof(Elf32_Ehdr)) ||
196                 (estate.e.elf32.e_phentsize != sizeof(Elf32_Phdr)) ||
197                 !ELF_CHECK_ARCH(estate.e.elf32)) {
198                 return 0;
199         }
200         printf("(ELF");
201         elf_freebsd_probe();
202         printf(")... ");
203         phdr_size = estate.e.elf32.e_phnum * estate.e.elf32.e_phentsize;
204         if (estate.e.elf32.e_phoff + phdr_size > len) {
205                 printf("ELF header outside first block\n");
206                 return dead_download;
207         }
208         if (phdr_size > sizeof(estate.p.dummy)) {
209                 printf("Program header too big\n");
210                 return dead_download;
211         }
212         memcpy(&estate.p.phdr32, data + estate.e.elf32.e_phoff, phdr_size);
213         if (estate.e.elf32.e_type == ET_DYN) {
214                 Elf32_Addr min, max, base_addr, delta, align;
215                 min = -1;
216                 max = 0;
217                 align = 1;
218                 for(estate.segment = 0; estate.segment < estate.e.elf32.e_phnum; estate.segment++) {
219                         Elf32_Addr val;
220                         if (estate.p.phdr32[estate.segment].p_type != PT_LOAD)
221                                 continue;
222                         val = estate.p.phdr32[estate.segment].p_paddr;
223                         if (val < min) {
224                                 min = val;
225                         }
226                         val += estate.p.phdr32[estate.segment].p_memsz;
227                         if (val > max) {
228                                 max = val;
229                         }
230                         if (estate.p.phdr32[estate.segment].p_align > align) {
231                                 align = estate.p.phdr32[estate.segment].p_align;
232                         }
233                 }
234                 if (align & (align -1)) {
235                         printf("ELF base address alignment is not a power of 2\n");
236                         return dead_download;
237                 }
238                 base_addr = find_segment(max - min, align);
239                 if (base_addr == ULONG_MAX) {
240                         printf("ELF base address not available for size %ld\n", max - min);
241                         return dead_download;
242                 }
243                 /* Compute the change in base address and fix up the addresses */
244                 delta = base_addr - min;
245                 for(estate.segment = 0; estate.segment < estate.e.elf32.e_phnum; estate.segment++) {
246                         /* Change the base address of the object to load */
247                         estate.p.phdr32[estate.segment].p_paddr += delta;
248                 }
249                 estate.e.elf32.e_entry += delta;
250         }
251 #if ELF_NOTES
252         /* Load ELF notes from the image */
253         estate.check_ip_checksum = 0;
254         for(estate.segment = 0; estate.segment < estate.e.elf32.e_phnum; estate.segment++) {
255                 if (estate.p.phdr32[estate.segment].p_type != PT_NOTE)
256                         continue;
257                 if (estate.p.phdr32[estate.segment].p_offset + estate.p.phdr32[estate.segment].p_filesz > len) {
258                         /* Ignore ELF notes outside of the first block */
259                         continue;
260                 }
261                 process_elf_notes(data, 
262                         estate.p.phdr32[estate.segment].p_offset, estate.p.phdr32[estate.segment].p_filesz);
263         }
264 #endif
265         /* Check for Etherboot related limitations.  Memory
266          * between _text and _end is not allowed.
267          * Reasons: the Etherboot code/data area.
268          */
269         for (estate.segment = 0; estate.segment < estate.e.elf32.e_phnum; estate.segment++) {
270                 unsigned long start, mid, end, istart, iend;
271                 if (estate.p.phdr32[estate.segment].p_type != PT_LOAD)
272                         continue;
273
274                 elf_freebsd_fixup_segment();
275
276                 start = estate.p.phdr32[estate.segment].p_paddr;
277                 mid = start + estate.p.phdr32[estate.segment].p_filesz;
278                 end = start + estate.p.phdr32[estate.segment].p_memsz;
279                 istart = estate.p.phdr32[estate.segment].p_offset;
280                 iend = istart + estate.p.phdr32[estate.segment].p_filesz;
281                 if (!prep_segment(start, mid, end, istart, iend)) {
282                         return dead_download;
283                 }
284                 if (!elf_prep_segment(start, mid, end, istart, iend)) {
285                         return dead_download;
286                 }
287         }
288         estate.segment = -1;
289         estate.loc = 0;
290         estate.skip = 0;
291         estate.toread = 0;
292         multiboot_init();
293         return elf32_download;
294 }
295
296 static sector_t elf32_download(unsigned char *data, unsigned int len, int eof)
297 {
298         unsigned long skip_sectors = 0;
299         unsigned int offset;    /* working offset in the current data block */
300         int i;
301
302         offset = 0;
303         do {
304                 if (estate.segment != -1) {
305                         if (estate.skip) {
306                                 if (estate.skip >= len - offset) {
307                                         estate.skip -= len - offset;
308                                         break;
309                                 }
310                                 offset += estate.skip;
311                                 estate.skip = 0;
312                         }
313                         
314                         if (estate.toread) {
315                                 unsigned int cplen;
316                                 cplen = len - offset;
317                                 if (cplen >= estate.toread) {
318                                         cplen = estate.toread;
319                                 }
320                                 memcpy(phys_to_virt(estate.curaddr), data+offset, cplen);
321                                 estate.curaddr += cplen;
322                                 estate.toread -= cplen;
323                                 offset += cplen;
324                                 if (estate.toread)
325                                         break;
326                                 elf_freebsd_find_segment_end();
327                         }
328                 }
329                 
330                 /* Data left, but current segment finished - look for the next
331                  * segment (in file offset order) that needs to be loaded. 
332                  * We can only seek forward, so select the program headers,
333                  * in the correct order.
334                  */
335                 estate.segment = -1;
336                 for (i = 0; i < estate.e.elf32.e_phnum; i++) {
337                         if (estate.p.phdr32[i].p_type != PT_LOAD)
338                                 continue;
339                         if (estate.p.phdr32[i].p_filesz == 0)
340                                 continue;
341                         if (estate.p.phdr32[i].p_offset < estate.loc + offset)
342                                 continue;       /* can't go backwards */
343                         if ((estate.segment != -1) &&
344                                 (estate.p.phdr32[i].p_offset >= estate.p.phdr32[estate.segment].p_offset))
345                                 continue;       /* search minimum file offset */
346                         estate.segment = i;
347                 }
348                 if (estate.segment == -1) {
349                         if (elf_freebsd_debug_loader(offset)) {
350                                 estate.segment = 0; /* -1 makes it not read anymore */
351                                 continue;
352                         }
353                         /* No more segments to be loaded, so just start the
354                          * kernel.  This saves a lot of network bandwidth if
355                          * debug info is in the kernel but not loaded.  */
356                         goto elf_startkernel;
357                         break;
358                 }
359                 estate.curaddr = estate.p.phdr32[estate.segment].p_paddr;
360                 estate.skip    = estate.p.phdr32[estate.segment].p_offset - (estate.loc + offset);
361                 estate.toread  = estate.p.phdr32[estate.segment].p_filesz;
362 #if ELF_DEBUG
363                 printf("PHDR %d, size %#lX, curaddr %#lX\n",
364                         estate.segment, estate.toread, estate.curaddr);
365 #endif
366         } while (offset < len);
367
368         estate.loc += len + (estate.skip & ~0x1ff);
369         skip_sectors = estate.skip >> 9;
370         estate.skip &= 0x1ff;
371         
372         if (eof) {
373                 unsigned long entry;
374                 unsigned long machine;
375 elf_startkernel:
376                 entry = estate.e.elf32.e_entry;
377                 machine = estate.e.elf32.e_machine;
378
379 #if ELF_NOTES
380                 if (estate.check_ip_checksum) {
381                         unsigned long bytes = 0;
382                         uint16_t sum, new_sum;
383
384                         sum = ipchksum(&estate.e.elf32, sizeof(estate.e.elf32));
385                         bytes = sizeof(estate.e.elf32);
386 #if ELF_DEBUG
387                         printf("Ehdr: %hx %hx sz: %lx bytes: %lx\n",
388                                 sum, sum, bytes, bytes);
389 #endif
390
391                         new_sum = ipchksum(estate.p.phdr32, sizeof(estate.p.phdr32[0]) * estate.e.elf32.e_phnum);
392                         sum = add_ipchksums(bytes, sum, new_sum);
393                         bytes += sizeof(estate.p.phdr32[0]) * estate.e.elf32.e_phnum;
394 #if ELF_DEBUG
395                         printf("Phdr: %hx %hx sz: %lx bytes: %lx\n",
396                                 new_sum, sum,
397                                 sizeof(estate.p.phdr32[0]) * estate.e.elf32.e_phnum, bytes);
398 #endif
399
400                         for(i = 0; i < estate.e.elf32.e_phnum; i++) {
401                                 if (estate.p.phdr32[i].p_type != PT_LOAD)
402                                         continue;
403                                 new_sum = ipchksum(phys_to_virt(estate.p.phdr32[i].p_paddr),
404                                                 estate.p.phdr32[i].p_memsz);
405                                 sum = add_ipchksums(bytes, sum, new_sum);
406                                 bytes += estate.p.phdr32[i].p_memsz;
407 #if ELF_DEBUG
408                         printf("seg%d: %hx %hx sz: %x bytes: %lx\n",
409                                 i, new_sum, sum,
410                                 estate.p.phdr32[i].p_memsz, bytes);
411 #endif
412
413                         }
414                         if (estate.ip_checksum != sum) {
415                                 printf("\nImage checksum: %hx != computed checksum: %hx\n",
416                                         estate.ip_checksum, sum);
417                                 longjmp(restart_etherboot, -2);
418                         }
419                 }
420 #endif
421                 done(1);
422                 /* Fixup the offset to the program header so you can find the program headers from
423                  * the ELF header mknbi needs this.
424                  */
425                 estate.e.elf32.e_phoff = (char *)&estate.p - (char *)&estate.e;
426                 elf_freebsd_boot(entry);
427                 elf_boot(machine,entry);
428         }
429         return skip_sectors;
430 }
431 #endif /* ELF_IMAGE */
432
433 #ifdef  ELF64_IMAGE
434 static sector_t elf64_download(unsigned char *data, unsigned int len, int eof);
435 static inline os_download_t elf64_probe(unsigned char *data, unsigned int len)
436 {
437         unsigned long phdr_size;
438         if (len < sizeof(estate.e.elf64)) {
439                 return 0;
440         }
441         memcpy(&estate.e.elf64, data, sizeof(estate.e.elf64));
442         if ((estate.e.elf64.e_ident[EI_MAG0] != ELFMAG0) ||
443                 (estate.e.elf64.e_ident[EI_MAG1] != ELFMAG1) ||
444                 (estate.e.elf64.e_ident[EI_MAG2] != ELFMAG2) ||
445                 (estate.e.elf64.e_ident[EI_MAG3] != ELFMAG3) ||
446                 (estate.e.elf64.e_ident[EI_CLASS] != ELFCLASS64) ||
447                 (estate.e.elf64.e_ident[EI_DATA] != ELFDATA_CURRENT) ||
448                 (estate.e.elf64.e_ident[EI_VERSION] != EV_CURRENT) ||
449                 (       (estate.e.elf64.e_type != ET_EXEC) &&
450                         (estate.e.elf64.e_type != ET_DYN)) ||
451                 (estate.e.elf64.e_version != EV_CURRENT) ||
452                 (estate.e.elf64.e_ehsize != sizeof(Elf64_Ehdr)) ||
453                 (estate.e.elf64.e_phentsize != sizeof(Elf64_Phdr)) ||
454                 !ELF_CHECK_ARCH(estate.e.elf64)) {
455                 return 0;
456         }
457         printf("(ELF64)... ");
458         phdr_size = estate.e.elf64.e_phnum * estate.e.elf64.e_phentsize;
459         if (estate.e.elf64.e_phoff + phdr_size > len) {
460                 printf("ELF header outside first block\n");
461                 return dead_download;
462         }
463         if (phdr_size > sizeof(estate.p.dummy)) {
464                 printf("Program header to big\n");
465                 return dead_download;
466         }
467         if (estate.e.elf64.e_entry > ULONG_MAX) {
468                 printf("ELF entry point exceeds address space\n");
469                 return dead_download;
470         }
471         memcpy(&estate.p.phdr64, data + estate.e.elf64.e_phoff, phdr_size);
472         if (estate.e.elf64.e_type == ET_DYN) {
473                 Elf64_Addr min, max, base_addr, delta, align;
474                 min = -1;
475                 max = 0;
476                 align = 1;
477                 for(estate.segment = 0; estate.segment < estate.e.elf64.e_phnum; estate.segment++) {
478                         Elf64_Addr val;
479                         if (estate.p.phdr64[estate.segment].p_type != PT_LOAD)
480                                 continue;
481                         val = estate.p.phdr64[estate.segment].p_paddr;
482                         if (val < min) {
483                                 min = val;
484                         }
485                         val += estate.p.phdr64[estate.segment].p_memsz;
486                         if (val > max) {
487                                 max = val;
488                         }
489                         if (estate.p.phdr64[estate.segment].p_align > align) {
490                                 align = estate.p.phdr64[estate.segment].p_align;
491                         }
492                 }
493                 if (align > ULONG_MAX) {
494                         printf("ELF base address alignment exceeds address space\n");
495                         return dead_download;
496                 }
497                 if (align & (align -1)) {
498                         printf("ELF base address alignment is not a power of 2\n");
499                         return dead_download;
500                 }
501                 if ((max - min) > ULONG_MAX) {
502                         printf("ELF size exceeds address space\n");
503                         return dead_download;
504                 }
505                 base_addr = find_segment(max - min, align);
506                 if (base_addr == ULONG_MAX) {
507                         printf("ELF base address not available for size %ld\n", max - min);
508                         return dead_download;
509                 }
510                 /* Compute the change in base address and fix up the addresses */
511                 delta = base_addr - min;
512                 for(estate.segment = 0; estate.segment < estate.e.elf64.e_phnum; estate.segment++) {
513                         /* Change the base address of the object to load */
514                         estate.p.phdr64[estate.segment].p_paddr += delta;
515                 }
516                 estate.e.elf64.e_entry += delta;
517         }
518 #if ELF_NOTES
519         /* Load ELF notes from the image */
520         estate.check_ip_checksum = 0;
521         for(estate.segment = 0; estate.segment < estate.e.elf64.e_phnum; estate.segment++) {
522                 if (estate.p.phdr64[estate.segment].p_type != PT_NOTE)
523                         continue;
524                 if (estate.p.phdr64[estate.segment].p_offset + estate.p.phdr64[estate.segment].p_filesz > len) {
525                         /* Ignore ELF notes outside of the first block */
526                         continue;
527                 }
528                 process_elf_notes(data, 
529                         estate.p.phdr64[estate.segment].p_offset, estate.p.phdr64[estate.segment].p_filesz);
530         }
531 #endif
532         /* Check for Etherboot related limitations.  Memory
533          * between _text and _end is not allowed.  
534          * Reasons: the Etherboot code/data area.
535          */
536         for (estate.segment = 0; estate.segment < estate.e.elf64.e_phnum; estate.segment++) {
537                 unsigned long start, mid, end, istart, iend;
538                 if (estate.p.phdr64[estate.segment].p_type != PT_LOAD) 
539                         continue;
540                 if ((estate.p.phdr64[estate.segment].p_paddr > ULONG_MAX) ||
541                         ((estate.p.phdr64[estate.segment].p_paddr + estate.p.phdr64[estate.segment].p_filesz) > ULONG_MAX) ||
542                         ((estate.p.phdr64[estate.segment].p_paddr + estate.p.phdr64[estate.segment].p_memsz) > ULONG_MAX)) {
543                         printf("ELF segment exceeds address space\n");
544                         return dead_download;
545                 }
546                 start = estate.p.phdr64[estate.segment].p_paddr;
547                 mid = start + estate.p.phdr64[estate.segment].p_filesz;
548                 end = start + estate.p.phdr64[estate.segment].p_memsz;
549                 istart = iend = ULONG_MAX;
550                 if ((estate.p.phdr64[estate.segment].p_offset < ULONG_MAX) &&
551                         ((estate.p.phdr64[estate.segment].p_offset + estate.p.phdr64[estate.segment].p_filesz) < ULONG_MAX))
552                 {
553                         istart = estate.p.phdr64[estate.segment].p_offset;
554                         iend   = istart + estate.p.phdr64[estate.segment].p_filesz;
555                 } 
556                 if (!prep_segment(start, mid, end, istart, iend)) {
557                         return dead_download;
558                 }
559                 if (!elf_prep_segment(start, mid, end, istart, iend)) {
560                         return dead_download;
561                 }
562         }
563         estate.segment = -1;
564         estate.loc = 0;
565         estate.skip = 0;
566         estate.toread = 0;
567         return elf64_download;
568 }
569
570 static sector_t elf64_download(unsigned char *data, unsigned int len, int eof)
571 {
572         unsigned long skip_sectors = 0;
573         unsigned int offset;    /* working offset in the current data block */
574         int i;
575
576         offset = 0;
577         do {
578                 if (estate.segment != -1) {
579                         if (estate.skip) {
580                                 if (estate.skip >= len - offset) {
581                                         estate.skip -= len - offset;
582                                         break;
583                                 }
584                                 offset += estate.skip;
585                                 estate.skip = 0;
586                         }
587                         
588                         if (estate.toread) {
589                                 unsigned int cplen;
590                                 cplen = len - offset;
591                                 if (cplen >= estate.toread) {
592                                         cplen = estate.toread;
593                                 }
594                                 memcpy(phys_to_virt(estate.curaddr), data+offset, cplen);
595                                 estate.curaddr += cplen;
596                                 estate.toread -= cplen;
597                                 offset += cplen;
598                                 if (estate.toread)
599                                         break;
600                         }
601                 }
602                 
603                 /* Data left, but current segment finished - look for the next
604                  * segment (in file offset order) that needs to be loaded. 
605                  * We can only seek forward, so select the program headers,
606                  * in the correct order.
607                  */
608                 estate.segment = -1;
609                 for (i = 0; i < estate.e.elf64.e_phnum; i++) {
610                         if (estate.p.phdr64[i].p_type != PT_LOAD)
611                                 continue;
612                         if (estate.p.phdr64[i].p_filesz == 0)
613                                 continue;
614                         if (estate.p.phdr64[i].p_offset < estate.loc + offset)
615                                 continue;       /* can't go backwards */
616                         if ((estate.segment != -1) &&
617                                 (estate.p.phdr64[i].p_offset >= estate.p.phdr64[estate.segment].p_offset))
618                                 continue;       /* search minimum file offset */
619                         estate.segment = i;
620                 }
621                 if (estate.segment == -1) {
622                         /* No more segments to be loaded, so just start the
623                          * kernel.  This saves a lot of network bandwidth if
624                          * debug info is in the kernel but not loaded.  */
625                         goto elf_startkernel;
626                         break;
627                 }
628                 estate.curaddr = estate.p.phdr64[estate.segment].p_paddr;
629                 estate.skip    = estate.p.phdr64[estate.segment].p_offset - (estate.loc + offset);
630                 estate.toread  = estate.p.phdr64[estate.segment].p_filesz;
631 #if ELF_DEBUG
632                 printf("PHDR %d, size %#lX, curaddr %#lX\n",
633                         estate.segment, estate.toread, estate.curaddr);
634 #endif
635         } while (offset < len);
636         
637         estate.loc += len + (estate.skip & ~0x1ff);
638         skip_sectors = estate.skip >> 9;
639         estate.skip &= 0x1ff;
640         
641         if (eof) {
642                 unsigned long entry;
643                 unsigned long machine;
644 elf_startkernel:
645                 entry = estate.e.elf64.e_entry;
646                 machine = estate.e.elf64.e_machine;
647 #if ELF_NOTES
648                 if (estate.check_ip_checksum) {
649                         unsigned long bytes = 0;
650                         uint16_t sum, new_sum;
651
652                         sum = ipchksum(&estate.e.elf64, sizeof(estate.e.elf64));
653                         bytes = sizeof(estate.e.elf64);
654 #if ELF_DEBUG
655                         printf("Ehdr: %hx %hx sz: %lx bytes: %lx\n",
656                                 sum, sum, bytes, bytes);
657 #endif
658
659                         new_sum = ipchksum(estate.p.phdr64, sizeof(estate.p.phdr64[0]) * estate.e.elf64.e_phnum);
660                         sum = add_ipchksums(bytes, sum, new_sum);
661                         bytes += sizeof(estate.p.phdr64[0]) * estate.e.elf64.e_phnum;
662 #if ELF_DEBUG
663                         printf("Phdr: %hx %hx sz: %lx bytes: %lx\n",
664                                 new_sum, sum,
665                                 sizeof(estate.p.phdr64[0]) * estate.e.elf64.e_phnum, bytes);
666 #endif
667
668                         for(i = 0; i < estate.e.elf64.e_phnum; i++) {
669                                 if (estate.p.phdr64[i].p_type != PT_LOAD)
670                                         continue;
671                                 new_sum = ipchksum(phys_to_virt(estate.p.phdr64[i].p_paddr),
672                                                 estate.p.phdr64[i].p_memsz);
673                                 sum = add_ipchksums(bytes, sum, new_sum);
674                                 bytes += estate.p.phdr64[i].p_memsz;
675 #if ELF_DEBUG
676                         printf("seg%d: %hx %hx sz: %x bytes: %lx\n",
677                                 i, new_sum, sum,
678                                 estate.p.phdr64[i].p_memsz, bytes);
679 #endif
680
681                         }
682                         if (estate.ip_checksum != sum) {
683                                 printf("\nImage checksum: %hx != computed checksum: %hx\n",
684                                         estate.ip_checksum, sum);
685                                 longjmp(restart_etherboot, -2);
686                         }
687                 }
688 #endif
689                 done(1);
690                 /* Fixup the offset to the program header so you can find the program headers from
691                  * the ELF header mknbi needs this.
692                  */
693                 estate.e.elf64.e_phoff = (char *)&estate.p - (char *)&estate.e;
694                 elf_boot(machine,entry);
695         }
696         return skip_sectors;
697 }
698
699 #endif /* ELF64_IMAGE */