4 #error ELF_CHECK_ARCH not defined
19 unsigned char dummy[1024];
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 */
27 int check_ip_checksum;
29 unsigned long ip_checksum_offset;
33 static struct elf_state estate;
35 static unsigned long find_segment(unsigned long size, unsigned long align)
38 /* Verify I have a power of 2 alignment */
39 if (align & (align - 1)) {
42 for(i = 0; i < meminfo.map_count; i++) {
43 unsigned long r_start, r_end;
44 if (meminfo.map[i].type != E820_RAM)
46 if ((meminfo.map[i].addr + meminfo.map[i].size) > ULONG_MAX) {
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)) {
62 if ((r_start > heap_ptr) && (r_start < heap_bot)) {
65 r_start = (r_start + align - 1) & ~(align - 1);
66 if ((r_end >= r_start) && ((r_end - r_start) >= size)) {
70 /* I did not find anything :( */
74 static void elf_boot(unsigned long machine, unsigned long entry)
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));
87 printf("Secondary program returned %d\n", result);
88 longjmp(restart_etherboot, result);
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
104 estate.ip_checksum = 0;
110 #define elf_prep_segment(start, mid, end, istart, iend) (1)
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;
124 program = version = 0;
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);
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) {
143 case EIN_PROGRAM_VERSION:
144 if (n_desc[hdr->n_descsz -1] == 0) {
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;
156 printf("Checksum: %hx\n", estate.ip_checksum);
163 printf("n_type: %x n_name(%d): %s n_desc(%d): %s\n",
165 hdr->n_namesz, n_name,
166 hdr->n_descsz, n_desc);
170 if (program && version) {
171 printf("\nLoading %s version: %s\n", program, version);
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)) {
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)) {
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;
218 for(estate.segment = 0; estate.segment < estate.e.elf32.e_phnum; estate.segment++) {
220 if (estate.p.phdr32[estate.segment].p_type != PT_LOAD)
222 val = estate.p.phdr32[estate.segment].p_paddr;
226 val += estate.p.phdr32[estate.segment].p_memsz;
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;
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)
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 */
261 process_elf_notes(data,
262 estate.p.phdr32[estate.segment].p_offset, estate.p.phdr32[estate.segment].p_filesz);
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)
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;
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 */
304 if (estate.segment != -1) {
306 if (estate.skip >= len - offset) {
307 estate.skip -= len - offset;
310 offset += estate.skip;
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;
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.
336 for (i = 0; i < estate.e.elf32.e_phnum; i++) {
337 if (estate.p.phdr32[i].p_type != PT_LOAD)
339 if (estate.p.phdr32[i].p_filesz == 0)
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 */
348 if (estate.segment == -1) {
349 if (elf_freebsd_debug_loader(offset)) {
350 estate.segment = 0; /* -1 makes it not read anymore */
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;
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;
363 printf("PHDR %d, size %#lX, curaddr %#lX\n",
364 estate.segment, estate.toread, estate.curaddr);
366 } while (offset < len);
368 estate.loc += len + (estate.skip & ~0x1ff);
369 skip_sectors = estate.skip >> 9;
370 estate.skip &= 0x1ff;
374 unsigned long machine;
376 entry = estate.e.elf32.e_entry;
377 machine = estate.e.elf32.e_machine;
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);
387 printf("Ehdr: %hx %hx sz: %lx bytes: %lx\n",
388 sum, sum, bytes, bytes);
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;
395 printf("Phdr: %hx %hx sz: %lx bytes: %lx\n",
397 sizeof(estate.p.phdr32[0]) * estate.e.elf32.e_phnum, bytes);
400 for(i = 0; i < estate.e.elf32.e_phnum; i++) {
401 if (estate.p.phdr32[i].p_type != PT_LOAD)
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;
408 printf("seg%d: %hx %hx sz: %x bytes: %lx\n",
410 estate.p.phdr32[i].p_memsz, bytes);
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);
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);
431 #endif /* ELF_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)) {
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)) {
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;
477 for(estate.segment = 0; estate.segment < estate.e.elf64.e_phnum; estate.segment++) {
479 if (estate.p.phdr64[estate.segment].p_type != PT_LOAD)
481 val = estate.p.phdr64[estate.segment].p_paddr;
485 val += estate.p.phdr64[estate.segment].p_memsz;
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;
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)
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 */
528 process_elf_notes(data,
529 estate.p.phdr64[estate.segment].p_offset, estate.p.phdr64[estate.segment].p_filesz);
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)
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;
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 */
578 if (estate.segment != -1) {
580 if (estate.skip >= len - offset) {
581 estate.skip -= len - offset;
584 offset += estate.skip;
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;
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.
609 for (i = 0; i < estate.e.elf64.e_phnum; i++) {
610 if (estate.p.phdr64[i].p_type != PT_LOAD)
612 if (estate.p.phdr64[i].p_filesz == 0)
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 */
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;
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;
632 printf("PHDR %d, size %#lX, curaddr %#lX\n",
633 estate.segment, estate.toread, estate.curaddr);
635 } while (offset < len);
637 estate.loc += len + (estate.skip & ~0x1ff);
638 skip_sectors = estate.skip >> 9;
639 estate.skip &= 0x1ff;
643 unsigned long machine;
645 entry = estate.e.elf64.e_entry;
646 machine = estate.e.elf64.e_machine;
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);
655 printf("Ehdr: %hx %hx sz: %lx bytes: %lx\n",
656 sum, sum, bytes, bytes);
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;
663 printf("Phdr: %hx %hx sz: %lx bytes: %lx\n",
665 sizeof(estate.p.phdr64[0]) * estate.e.elf64.e_phnum, bytes);
668 for(i = 0; i < estate.e.elf64.e_phnum; i++) {
669 if (estate.p.phdr64[i].p_type != PT_LOAD)
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;
676 printf("seg%d: %hx %hx sz: %x bytes: %lx\n",
678 estate.p.phdr64[i].p_memsz, bytes);
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);
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);
699 #endif /* ELF64_IMAGE */