Start a new LOG file in preparation for release
[gpxe.git] / src / core / elf_loader.c
blob85b60e8a38c2a2352e239528d357aa73fb177be2
1 #include "elf.h"
3 #ifndef ELF_CHECK_ARCH
4 #error ELF_CHECK_ARCH not defined
5 #endif
7 #define ELF_NOTES 1
8 #define ELF_DEBUG 0
10 struct elf_state
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
33 static struct elf_state estate;
35 static unsigned long find_segment(unsigned long size, unsigned long align)
37 unsigned i;
38 /* Verify I have a power of 2 alignment */
39 if (align & (align - 1)) {
40 return ULONG_MAX;
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;
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);
55 if ((r_start > virt_to_phys(_text)) && (r_start < virt_to_phys(_end))) {
56 r_start = virt_to_phys(_end);
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;
62 if ((r_start > heap_ptr) && (r_start < heap_bot)) {
63 r_start = heap_ptr;
65 r_start = (r_start + align - 1) & ~(align - 1);
66 if ((r_end >= r_start) && ((r_end - r_start) >= size)) {
67 return r_start;
70 /* I did not find anything :( */
71 return ULONG_MAX;
74 static void elf_boot(unsigned long machine, unsigned long entry)
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.
82 hdr = prepare_boot_params(&estate.e);
83 result = elf_start(machine, entry, virt_to_phys(hdr));
84 if (result == 0) {
85 result = -1;
87 printf("Secondary program returned %d\n", result);
88 longjmp(restart_etherboot, result);
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)
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.
104 estate.ip_checksum = 0;
107 return 1;
109 #else
110 #define elf_prep_segment(start, mid, end, istart, iend) (1)
111 #endif
114 #if ELF_NOTES
115 static void process_elf_notes(unsigned char *header,
116 unsigned long offset, unsigned long length)
118 unsigned char *note, *end;
119 char *program, *version;
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;
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;
142 break;
143 case EIN_PROGRAM_VERSION:
144 if (n_desc[hdr->n_descsz -1] == 0) {
145 version = n_desc;
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.
154 estate.ip_checksum_offset = n_desc - header;
155 #if ELF_DEBUG
156 printf("Checksum: %hx\n", estate.ip_checksum);
157 #endif
159 break;
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;
170 if (program && version) {
171 printf("\nLoading %s version: %s\n", program, version);
174 #endif
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)
180 unsigned long phdr_size;
181 if (len < sizeof(estate.e.elf32)) {
182 return 0;
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;
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;
208 if (phdr_size > sizeof(estate.p.dummy)) {
209 printf("Program header too big\n");
210 return dead_download;
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;
226 val += estate.p.phdr32[estate.segment].p_memsz;
227 if (val > max) {
228 max = val;
230 if (estate.p.phdr32[estate.segment].p_align > align) {
231 align = estate.p.phdr32[estate.segment].p_align;
234 if (align & (align -1)) {
235 printf("ELF base address alignment is not a power of 2\n");
236 return dead_download;
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;
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;
249 estate.e.elf32.e_entry += delta;
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;
261 process_elf_notes(data,
262 estate.p.phdr32[estate.segment].p_offset, estate.p.phdr32[estate.segment].p_filesz);
264 #endif
265 /* Check for Etherboot related limitations. Memory
266 * between _text and _end is not allowed.
267 * Reasons: the Etherboot code/data area.
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;
274 elf_freebsd_fixup_segment();
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;
284 if (!elf_prep_segment(start, mid, end, istart, iend)) {
285 return dead_download;
288 estate.segment = -1;
289 estate.loc = 0;
290 estate.skip = 0;
291 estate.toread = 0;
292 multiboot_init();
293 return elf32_download;
296 static sector_t elf32_download(unsigned char *data, unsigned int len, int eof)
298 unsigned long skip_sectors = 0;
299 unsigned int offset; /* working offset in the current data block */
300 int i;
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;
310 offset += estate.skip;
311 estate.skip = 0;
314 if (estate.toread) {
315 unsigned int cplen;
316 cplen = len - offset;
317 if (cplen >= estate.toread) {
318 cplen = estate.toread;
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();
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.
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;
348 if (estate.segment == -1) {
349 if (elf_freebsd_debug_loader(offset)) {
350 estate.segment = 0; /* -1 makes it not read anymore */
351 continue;
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;
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);
368 estate.loc += len + (estate.skip & ~0x1ff);
369 skip_sectors = estate.skip >> 9;
370 estate.skip &= 0x1ff;
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;
379 #if ELF_NOTES
380 if (estate.check_ip_checksum) {
381 unsigned long bytes = 0;
382 uint16_t sum, new_sum;
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
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
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
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);
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.
425 estate.e.elf32.e_phoff = (char *)&estate.p - (char *)&estate.e;
426 elf_freebsd_boot(entry);
427 elf_boot(machine,entry);
429 return skip_sectors;
431 #endif /* ELF_IMAGE */
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)
437 unsigned long phdr_size;
438 if (len < sizeof(estate.e.elf64)) {
439 return 0;
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;
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;
463 if (phdr_size > sizeof(estate.p.dummy)) {
464 printf("Program header to big\n");
465 return dead_download;
467 if (estate.e.elf64.e_entry > ULONG_MAX) {
468 printf("ELF entry point exceeds address space\n");
469 return dead_download;
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;
485 val += estate.p.phdr64[estate.segment].p_memsz;
486 if (val > max) {
487 max = val;
489 if (estate.p.phdr64[estate.segment].p_align > align) {
490 align = estate.p.phdr64[estate.segment].p_align;
493 if (align > ULONG_MAX) {
494 printf("ELF base address alignment exceeds address space\n");
495 return dead_download;
497 if (align & (align -1)) {
498 printf("ELF base address alignment is not a power of 2\n");
499 return dead_download;
501 if ((max - min) > ULONG_MAX) {
502 printf("ELF size exceeds address space\n");
503 return dead_download;
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;
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;
516 estate.e.elf64.e_entry += delta;
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;
528 process_elf_notes(data,
529 estate.p.phdr64[estate.segment].p_offset, estate.p.phdr64[estate.segment].p_filesz);
531 #endif
532 /* Check for Etherboot related limitations. Memory
533 * between _text and _end is not allowed.
534 * Reasons: the Etherboot code/data area.
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;
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))
553 istart = estate.p.phdr64[estate.segment].p_offset;
554 iend = istart + estate.p.phdr64[estate.segment].p_filesz;
556 if (!prep_segment(start, mid, end, istart, iend)) {
557 return dead_download;
559 if (!elf_prep_segment(start, mid, end, istart, iend)) {
560 return dead_download;
563 estate.segment = -1;
564 estate.loc = 0;
565 estate.skip = 0;
566 estate.toread = 0;
567 return elf64_download;
570 static sector_t elf64_download(unsigned char *data, unsigned int len, int eof)
572 unsigned long skip_sectors = 0;
573 unsigned int offset; /* working offset in the current data block */
574 int i;
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;
584 offset += estate.skip;
585 estate.skip = 0;
588 if (estate.toread) {
589 unsigned int cplen;
590 cplen = len - offset;
591 if (cplen >= estate.toread) {
592 cplen = estate.toread;
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;
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.
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;
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;
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);
637 estate.loc += len + (estate.skip & ~0x1ff);
638 skip_sectors = estate.skip >> 9;
639 estate.skip &= 0x1ff;
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;
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
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
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
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);
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.
693 estate.e.elf64.e_phoff = (char *)&estate.p - (char *)&estate.e;
694 elf_boot(machine,entry);
696 return skip_sectors;
699 #endif /* ELF64_IMAGE */