Merge from Etherboot 5.4
[people/xl0/gpxe-arm.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         multiboot_probe(data, len);
203         printf(")... ");
204         phdr_size = estate.e.elf32.e_phnum * estate.e.elf32.e_phentsize;
205         if (estate.e.elf32.e_phoff + phdr_size > len) {
206                 printf("ELF header outside first block\n");
207                 return dead_download;
208         }
209         if (phdr_size > sizeof(estate.p.dummy)) {
210                 printf("Program header to big\n");
211                 return dead_download;
212         }
213         memcpy(&estate.p.phdr32, data + estate.e.elf32.e_phoff, phdr_size);
214         if (estate.e.elf32.e_type == ET_DYN) {
215                 Elf32_Addr min, max, base_addr, delta, align;
216                 min = -1;
217                 max = 0;
218                 align = 1;
219                 for(estate.segment = 0; estate.segment < estate.e.elf32.e_phnum; estate.segment++) {
220                         Elf32_Addr val;
221                         if (estate.p.phdr32[estate.segment].p_type != PT_LOAD)
222                                 continue;
223                         val = estate.p.phdr32[estate.segment].p_paddr;
224                         if (val < min) {
225                                 min = val;
226                         }
227                         val += estate.p.phdr32[estate.segment].p_memsz;
228                         if (val > max) {
229                                 max = val;
230                         }
231                         if (estate.p.phdr32[estate.segment].p_align > align) {
232                                 align = estate.p.phdr32[estate.segment].p_align;
233                         }
234                 }
235                 if (align & (align -1)) {
236                         printf("ELF base address alignment is not a power of 2\n");
237                         return dead_download;
238                 }
239                 base_addr = find_segment(max - min, align);
240                 if (base_addr == ULONG_MAX) {
241                         printf("ELF base address not available for size %ld\n", max - min);
242                         return dead_download;
243                 }
244                 /* Compute the change in base address and fix up the addresses */
245                 delta = base_addr - min;
246                 for(estate.segment = 0; estate.segment < estate.e.elf32.e_phnum; estate.segment++) {
247                         /* Change the base address of the object to load */
248                         estate.p.phdr32[estate.segment].p_paddr += delta;
249                 }
250                 estate.e.elf32.e_entry += delta;
251         }
252 #if ELF_NOTES
253         /* Load ELF notes from the image */
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         return elf32_download;
293 }
294
295 static sector_t elf32_download(unsigned char *data, unsigned int len, int eof)
296 {
297         unsigned long skip_sectors = 0;
298         unsigned int offset;    /* working offset in the current data block */
299         int i;
300
301         offset = 0;
302         do {
303                 if (estate.segment != -1) {
304                         if (estate.skip) {
305                                 if (estate.skip >= len - offset) {
306                                         estate.skip -= len - offset;
307                                         break;
308                                 }
309                                 offset += estate.skip;
310                                 estate.skip = 0;
311                         }
312                         
313                         if (estate.toread) {
314                                 unsigned int cplen;
315                                 cplen = len - offset;
316                                 if (cplen >= estate.toread) {
317                                         cplen = estate.toread;
318                                 }
319                                 memcpy(phys_to_virt(estate.curaddr), data+offset, cplen);
320                                 estate.curaddr += cplen;
321                                 estate.toread -= cplen;
322                                 offset += cplen;
323                                 if (estate.toread)
324                                         break;
325                                 elf_freebsd_find_segment_end();
326                         }
327                 }
328                 
329                 /* Data left, but current segment finished - look for the next
330                  * segment (in file offset order) that needs to be loaded. 
331                  * We can only seek forward, so select the program headers,
332                  * in the correct order.
333                  */
334                 estate.segment = -1;
335                 for (i = 0; i < estate.e.elf32.e_phnum; i++) {
336                         if (estate.p.phdr32[i].p_type != PT_LOAD)
337                                 continue;
338                         if (estate.p.phdr32[i].p_filesz == 0)
339                                 continue;
340                         if (estate.p.phdr32[i].p_offset < estate.loc + offset)
341                                 continue;       /* can't go backwards */
342                         if ((estate.segment != -1) &&
343                                 (estate.p.phdr32[i].p_offset >= estate.p.phdr32[estate.segment].p_offset))
344                                 continue;       /* search minimum file offset */
345                         estate.segment = i;
346                 }
347                 if (estate.segment == -1) {
348                         if (elf_freebsd_debug_loader(offset)) {
349                                 estate.segment = 0; /* -1 makes it not read anymore */
350                                 continue;
351                         }
352                         /* No more segments to be loaded, so just start the
353                          * kernel.  This saves a lot of network bandwidth if
354                          * debug info is in the kernel but not loaded.  */
355                         goto elf_startkernel;
356                         break;
357                 }
358                 estate.curaddr = estate.p.phdr32[estate.segment].p_paddr;
359                 estate.skip    = estate.p.phdr32[estate.segment].p_offset - (estate.loc + offset);
360                 estate.toread  = estate.p.phdr32[estate.segment].p_filesz;
361 #if ELF_DEBUG
362                 printf("PHDR %d, size %#lX, curaddr %#lX\n",
363                         estate.segment, estate.toread, estate.curaddr);
364 #endif
365         } while (offset < len);
366
367         estate.loc += len + (estate.skip & ~0x1ff);
368         skip_sectors = estate.skip >> 9;
369         estate.skip &= 0x1ff;
370         
371         if (eof) {
372                 unsigned long entry;
373                 unsigned long machine;
374 elf_startkernel:
375                 entry = estate.e.elf32.e_entry;
376                 machine = estate.e.elf32.e_machine;
377
378 #if ELF_NOTES
379                 if (estate.check_ip_checksum) {
380                         unsigned long bytes = 0;
381                         uint16_t sum, new_sum;
382
383                         sum = ipchksum(&estate.e.elf32, sizeof(estate.e.elf32));
384                         bytes = sizeof(estate.e.elf32);
385 #if ELF_DEBUG
386                         printf("Ehdr: %hx %hx sz: %lx bytes: %lx\n",
387                                 sum, sum, bytes, bytes);
388 #endif
389
390                         new_sum = ipchksum(estate.p.phdr32, sizeof(estate.p.phdr32[0]) * estate.e.elf32.e_phnum);
391                         sum = add_ipchksums(bytes, sum, new_sum);
392                         bytes += sizeof(estate.p.phdr32[0]) * estate.e.elf32.e_phnum;
393 #if ELF_DEBUG
394                         printf("Phdr: %hx %hx sz: %lx bytes: %lx\n",
395                                 new_sum, sum,
396                                 sizeof(estate.p.phdr32[0]) * estate.e.elf32.e_phnum, bytes);
397 #endif
398
399                         for(i = 0; i < estate.e.elf32.e_phnum; i++) {
400                                 if (estate.p.phdr32[i].p_type != PT_LOAD)
401                                         continue;
402                                 new_sum = ipchksum(phys_to_virt(estate.p.phdr32[i].p_paddr),
403                                                 estate.p.phdr32[i].p_memsz);
404                                 sum = add_ipchksums(bytes, sum, new_sum);
405                                 bytes += estate.p.phdr32[i].p_memsz;
406 #if ELF_DEBUG
407                         printf("seg%d: %hx %hx sz: %x bytes: %lx\n",
408                                 i, new_sum, sum,
409                                 estate.p.phdr32[i].p_memsz, bytes);
410 #endif
411
412                         }
413                         if (estate.ip_checksum != sum) {
414                                 printf("\nImage checksum: %hx != computed checksum: %hx\n",
415                                         estate.ip_checksum, sum);
416                                 longjmp(restart_etherboot, -2);
417                         }
418                 }
419 #endif
420                 done(1);
421                 /* Fixup the offset to the program header so you can find the program headers from
422                  * the ELF header mknbi needs this.
423                  */
424                 estate.e.elf32.e_phoff = (char *)&estate.p - (char *)&estate.e;
425                 elf_freebsd_boot(entry);
426                 elf_boot(machine,entry);
427         }
428         return skip_sectors;
429 }
430 #endif /* ELF_IMAGE */
431
432 #ifdef  ELF64_IMAGE
433 static sector_t elf64_download(unsigned char *data, unsigned int len, int eof);
434 static inline os_download_t elf64_probe(unsigned char *data, unsigned int len)
435 {
436         unsigned long phdr_size;
437         if (len < sizeof(estate.e.elf64)) {
438                 return 0;
439         }
440         memcpy(&estate.e.elf64, data, sizeof(estate.e.elf64));
441         if ((estate.e.elf64.e_ident[EI_MAG0] != ELFMAG0) ||
442                 (estate.e.elf64.e_ident[EI_MAG1] != ELFMAG1) ||
443                 (estate.e.elf64.e_ident[EI_MAG2] != ELFMAG2) ||
444                 (estate.e.elf64.e_ident[EI_MAG3] != ELFMAG3) ||
445                 (estate.e.elf64.e_ident[EI_CLASS] != ELFCLASS64) ||
446                 (estate.e.elf64.e_ident[EI_DATA] != ELFDATA_CURRENT) ||
447                 (estate.e.elf64.e_ident[EI_VERSION] != EV_CURRENT) ||
448                 (       (estate.e.elf64.e_type != ET_EXEC) &&
449                         (estate.e.elf64.e_type != ET_DYN)) ||
450                 (estate.e.elf64.e_version != EV_CURRENT) ||
451                 (estate.e.elf64.e_ehsize != sizeof(Elf64_Ehdr)) ||
452                 (estate.e.elf64.e_phentsize != sizeof(Elf64_Phdr)) ||
453                 !ELF_CHECK_ARCH(estate.e.elf64)) {
454                 return 0;
455         }
456         printf("(ELF64)... ");
457         phdr_size = estate.e.elf64.e_phnum * estate.e.elf64.e_phentsize;
458         if (estate.e.elf64.e_phoff + phdr_size > len) {
459                 printf("ELF header outside first block\n");
460                 return dead_download;
461         }
462         if (phdr_size > sizeof(estate.p.dummy)) {
463                 printf("Program header to big\n");
464                 return dead_download;
465         }
466         if (estate.e.elf64.e_entry > ULONG_MAX) {
467                 printf("ELF entry point exceeds address space\n");
468                 return dead_download;
469         }
470         memcpy(&estate.p.phdr64, data + estate.e.elf64.e_phoff, phdr_size);
471         if (estate.e.elf64.e_type == ET_DYN) {
472                 Elf64_Addr min, max, base_addr, delta, align;
473                 min = -1;
474                 max = 0;
475                 align = 1;
476                 for(estate.segment = 0; estate.segment < estate.e.elf64.e_phnum; estate.segment++) {
477                         Elf64_Addr val;
478                         if (estate.p.phdr64[estate.segment].p_type != PT_LOAD)
479                                 continue;
480                         val = estate.p.phdr64[estate.segment].p_paddr;
481                         if (val < min) {
482                                 min = val;
483                         }
484                         val += estate.p.phdr64[estate.segment].p_memsz;
485                         if (val > max) {
486                                 max = val;
487                         }
488                         if (estate.p.phdr64[estate.segment].p_align > align) {
489                                 align = estate.p.phdr64[estate.segment].p_align;
490                         }
491                 }
492                 if (align > ULONG_MAX) {
493                         printf("ELF base address alignment exceeds address space\n");
494                         return dead_download;
495                 }
496                 if (align & (align -1)) {
497                         printf("ELF base address alignment is not a power of 2\n");
498                         return dead_download;
499                 }
500                 if ((max - min) > ULONG_MAX) {
501                         printf("ELF size exceeds address space\n");
502                         return dead_download;
503                 }
504                 base_addr = find_segment(max - min, align);
505                 if (base_addr == ULONG_MAX) {
506                         printf("ELF base address not available for size %ld\n", max - min);
507                         return dead_download;
508                 }
509                 /* Compute the change in base address and fix up the addresses */
510                 delta = base_addr - min;
511                 for(estate.segment = 0; estate.segment < estate.e.elf64.e_phnum; estate.segment++) {
512                         /* Change the base address of the object to load */
513                         estate.p.phdr64[estate.segment].p_paddr += delta;
514                 }
515                 estate.e.elf64.e_entry += delta;
516         }
517 #if ELF_NOTES
518         /* Load ELF notes from the image */
519         for(estate.segment = 0; estate.segment < estate.e.elf64.e_phnum; estate.segment++) {
520                 if (estate.p.phdr64[estate.segment].p_type != PT_NOTE)
521                         continue;
522                 if (estate.p.phdr64[estate.segment].p_offset + estate.p.phdr64[estate.segment].p_filesz > len) {
523                         /* Ignore ELF notes outside of the first block */
524                         continue;
525                 }
526                 process_elf_notes(data, 
527                         estate.p.phdr64[estate.segment].p_offset, estate.p.phdr64[estate.segment].p_filesz);
528         }
529 #endif
530         /* Check for Etherboot related limitations.  Memory
531          * between _text and _end is not allowed.  
532          * Reasons: the Etherboot code/data area.
533          */
534         for (estate.segment = 0; estate.segment < estate.e.elf64.e_phnum; estate.segment++) {
535                 unsigned long start, mid, end, istart, iend;
536                 if (estate.p.phdr64[estate.segment].p_type != PT_LOAD) 
537                         continue;
538                 if ((estate.p.phdr64[estate.segment].p_paddr > ULONG_MAX) ||
539                         ((estate.p.phdr64[estate.segment].p_paddr + estate.p.phdr64[estate.segment].p_filesz) > ULONG_MAX) ||
540                         ((estate.p.phdr64[estate.segment].p_paddr + estate.p.phdr64[estate.segment].p_memsz) > ULONG_MAX)) {
541                         printf("ELF segment exceeds address space\n");
542                         return dead_download;
543                 }
544                 start = estate.p.phdr64[estate.segment].p_paddr;
545                 mid = start + estate.p.phdr64[estate.segment].p_filesz;
546                 end = start + estate.p.phdr64[estate.segment].p_memsz;
547                 istart = iend = ULONG_MAX;
548                 if ((estate.p.phdr64[estate.segment].p_offset < ULONG_MAX) &&
549                         ((estate.p.phdr64[estate.segment].p_offset + estate.p.phdr64[estate.segment].p_filesz) < ULONG_MAX))
550                 {
551                         istart = estate.p.phdr64[estate.segment].p_offset;
552                         iend   = istart + estate.p.phdr64[estate.segment].p_filesz;
553                 } 
554                 if (!prep_segment(start, mid, end, istart, iend)) {
555                         return dead_download;
556                 }
557                 if (!elf_prep_segment(start, mid, end, istart, iend)) {
558                         return dead_download;
559                 }
560         }
561         estate.segment = -1;
562         estate.loc = 0;
563         estate.skip = 0;
564         estate.toread = 0;
565         return elf64_download;
566 }
567
568 static sector_t elf64_download(unsigned char *data, unsigned int len, int eof)
569 {
570         unsigned long skip_sectors = 0;
571         unsigned int offset;    /* working offset in the current data block */
572         int i;
573
574         offset = 0;
575         do {
576                 if (estate.segment != -1) {
577                         if (estate.skip) {
578                                 if (estate.skip >= len - offset) {
579                                         estate.skip -= len - offset;
580                                         break;
581                                 }
582                                 offset += estate.skip;
583                                 estate.skip = 0;
584                         }
585                         
586                         if (estate.toread) {
587                                 unsigned int cplen;
588                                 cplen = len - offset;
589                                 if (cplen >= estate.toread) {
590                                         cplen = estate.toread;
591                                 }
592                                 memcpy(phys_to_virt(estate.curaddr), data+offset, cplen);
593                                 estate.curaddr += cplen;
594                                 estate.toread -= cplen;
595                                 offset += cplen;
596                                 if (estate.toread)
597                                         break;
598                         }
599                 }
600                 
601                 /* Data left, but current segment finished - look for the next
602                  * segment (in file offset order) that needs to be loaded. 
603                  * We can only seek forward, so select the program headers,
604                  * in the correct order.
605                  */
606                 estate.segment = -1;
607                 for (i = 0; i < estate.e.elf64.e_phnum; i++) {
608                         if (estate.p.phdr64[i].p_type != PT_LOAD)
609                                 continue;
610                         if (estate.p.phdr64[i].p_filesz == 0)
611                                 continue;
612                         if (estate.p.phdr64[i].p_offset < estate.loc + offset)
613                                 continue;       /* can't go backwards */
614                         if ((estate.segment != -1) &&
615                                 (estate.p.phdr64[i].p_offset >= estate.p.phdr64[estate.segment].p_offset))
616                                 continue;       /* search minimum file offset */
617                         estate.segment = i;
618                 }
619                 if (estate.segment == -1) {
620                         /* No more segments to be loaded, so just start the
621                          * kernel.  This saves a lot of network bandwidth if
622                          * debug info is in the kernel but not loaded.  */
623                         goto elf_startkernel;
624                         break;
625                 }
626                 estate.curaddr = estate.p.phdr64[estate.segment].p_paddr;
627                 estate.skip    = estate.p.phdr64[estate.segment].p_offset - (estate.loc + offset);
628                 estate.toread  = estate.p.phdr64[estate.segment].p_filesz;
629 #if ELF_DEBUG
630                 printf("PHDR %d, size %#lX, curaddr %#lX\n",
631                         estate.segment, estate.toread, estate.curaddr);
632 #endif
633         } while (offset < len);
634         
635         estate.loc += len + (estate.skip & ~0x1ff);
636         skip_sectors = estate.skip >> 9;
637         estate.skip &= 0x1ff;
638         
639         if (eof) {
640                 unsigned long entry;
641                 unsigned long machine;
642 elf_startkernel:
643                 entry = estate.e.elf64.e_entry;
644                 machine = estate.e.elf64.e_machine;
645 #if ELF_NOTES
646                 if (estate.check_ip_checksum) {
647                         unsigned long bytes = 0;
648                         uint16_t sum, new_sum;
649
650                         sum = ipchksum(&estate.e.elf64, sizeof(estate.e.elf64));
651                         bytes = sizeof(estate.e.elf64);
652 #if ELF_DEBUG
653                         printf("Ehdr: %hx %hx sz: %lx bytes: %lx\n",
654                                 sum, sum, bytes, bytes);
655 #endif
656
657                         new_sum = ipchksum(estate.p.phdr64, sizeof(estate.p.phdr64[0]) * estate.e.elf64.e_phnum);
658                         sum = add_ipchksums(bytes, sum, new_sum);
659                         bytes += sizeof(estate.p.phdr64[0]) * estate.e.elf64.e_phnum;
660 #if ELF_DEBUG
661                         printf("Phdr: %hx %hx sz: %lx bytes: %lx\n",
662                                 new_sum, sum,
663                                 sizeof(estate.p.phdr64[0]) * estate.e.elf64.e_phnum, bytes);
664 #endif
665
666                         for(i = 0; i < estate.e.elf64.e_phnum; i++) {
667                                 if (estate.p.phdr64[i].p_type != PT_LOAD)
668                                         continue;
669                                 new_sum = ipchksum(phys_to_virt(estate.p.phdr64[i].p_paddr),
670                                                 estate.p.phdr64[i].p_memsz);
671                                 sum = add_ipchksums(bytes, sum, new_sum);
672                                 bytes += estate.p.phdr64[i].p_memsz;
673 #if ELF_DEBUG
674                         printf("seg%d: %hx %hx sz: %x bytes: %lx\n",
675                                 i, new_sum, sum,
676                                 estate.p.phdr64[i].p_memsz, bytes);
677 #endif
678
679                         }
680                         if (estate.ip_checksum != sum) {
681                                 printf("\nImage checksum: %hx != computed checksum: %hx\n",
682                                         estate.ip_checksum, sum);
683                                 longjmp(restart_etherboot, -2);
684                         }
685                 }
686 #endif
687                 done(1);
688                 /* Fixup the offset to the program header so you can find the program headers from
689                  * the ELF header mknbi needs this.
690                  */
691                 estate.e.elf64.e_phoff = (char *)&estate.p - (char *)&estate.e;
692                 elf_boot(machine,entry);
693         }
694         return skip_sectors;
695 }
696
697 #endif /* ELF64_IMAGE */