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)) {
202 multiboot_probe(data, len);
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;
209 if (phdr_size > sizeof(estate.p.dummy)) {
210 printf("Program header to big\n");
211 return dead_download;
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;
219 for(estate.segment = 0; estate.segment < estate.e.elf32.e_phnum; estate.segment++) {
221 if (estate.p.phdr32[estate.segment].p_type != PT_LOAD)
223 val = estate.p.phdr32[estate.segment].p_paddr;
227 val += estate.p.phdr32[estate.segment].p_memsz;
231 if (estate.p.phdr32[estate.segment].p_align > align) {
232 align = estate.p.phdr32[estate.segment].p_align;
235 if (align & (align -1)) {
236 printf("ELF base address alignment is not a power of 2\n");
237 return dead_download;
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;
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;
250 estate.e.elf32.e_entry += delta;
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)
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;
292 return elf32_download;
295 static sector_t elf32_download(unsigned char *data, unsigned int len, int eof)
297 unsigned long skip_sectors = 0;
298 unsigned int offset; /* working offset in the current data block */
303 if (estate.segment != -1) {
305 if (estate.skip >= len - offset) {
306 estate.skip -= len - offset;
309 offset += estate.skip;
315 cplen = len - offset;
316 if (cplen >= estate.toread) {
317 cplen = estate.toread;
319 memcpy(phys_to_virt(estate.curaddr), data+offset, cplen);
320 estate.curaddr += cplen;
321 estate.toread -= cplen;
325 elf_freebsd_find_segment_end();
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.
335 for (i = 0; i < estate.e.elf32.e_phnum; i++) {
336 if (estate.p.phdr32[i].p_type != PT_LOAD)
338 if (estate.p.phdr32[i].p_filesz == 0)
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 */
347 if (estate.segment == -1) {
348 if (elf_freebsd_debug_loader(offset)) {
349 estate.segment = 0; /* -1 makes it not read anymore */
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;
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;
362 printf("PHDR %d, size %#lX, curaddr %#lX\n",
363 estate.segment, estate.toread, estate.curaddr);
365 } while (offset < len);
367 estate.loc += len + (estate.skip & ~0x1ff);
368 skip_sectors = estate.skip >> 9;
369 estate.skip &= 0x1ff;
373 unsigned long machine;
375 entry = estate.e.elf32.e_entry;
376 machine = estate.e.elf32.e_machine;
379 if (estate.check_ip_checksum) {
380 unsigned long bytes = 0;
381 uint16_t sum, new_sum;
383 sum = ipchksum(&estate.e.elf32, sizeof(estate.e.elf32));
384 bytes = sizeof(estate.e.elf32);
386 printf("Ehdr: %hx %hx sz: %lx bytes: %lx\n",
387 sum, sum, bytes, bytes);
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;
394 printf("Phdr: %hx %hx sz: %lx bytes: %lx\n",
396 sizeof(estate.p.phdr32[0]) * estate.e.elf32.e_phnum, bytes);
399 for(i = 0; i < estate.e.elf32.e_phnum; i++) {
400 if (estate.p.phdr32[i].p_type != PT_LOAD)
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;
407 printf("seg%d: %hx %hx sz: %x bytes: %lx\n",
409 estate.p.phdr32[i].p_memsz, bytes);
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);
421 /* Fixup the offset to the program header so you can find the program headers from
422 * the ELF header mknbi needs this.
424 estate.e.elf32.e_phoff = (char *)&estate.p - (char *)&estate.e;
425 elf_freebsd_boot(entry);
426 elf_boot(machine,entry);
430 #endif /* ELF_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)
436 unsigned long phdr_size;
437 if (len < sizeof(estate.e.elf64)) {
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)) {
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;
462 if (phdr_size > sizeof(estate.p.dummy)) {
463 printf("Program header to big\n");
464 return dead_download;
466 if (estate.e.elf64.e_entry > ULONG_MAX) {
467 printf("ELF entry point exceeds address space\n");
468 return dead_download;
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;
476 for(estate.segment = 0; estate.segment < estate.e.elf64.e_phnum; estate.segment++) {
478 if (estate.p.phdr64[estate.segment].p_type != PT_LOAD)
480 val = estate.p.phdr64[estate.segment].p_paddr;
484 val += estate.p.phdr64[estate.segment].p_memsz;
488 if (estate.p.phdr64[estate.segment].p_align > align) {
489 align = estate.p.phdr64[estate.segment].p_align;
492 if (align > ULONG_MAX) {
493 printf("ELF base address alignment exceeds address space\n");
494 return dead_download;
496 if (align & (align -1)) {
497 printf("ELF base address alignment is not a power of 2\n");
498 return dead_download;
500 if ((max - min) > ULONG_MAX) {
501 printf("ELF size exceeds address space\n");
502 return dead_download;
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;
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;
515 estate.e.elf64.e_entry += delta;
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)
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 */
526 process_elf_notes(data,
527 estate.p.phdr64[estate.segment].p_offset, estate.p.phdr64[estate.segment].p_filesz);
530 /* Check for Etherboot related limitations. Memory
531 * between _text and _end is not allowed.
532 * Reasons: the Etherboot code/data area.
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)
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;
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))
551 istart = estate.p.phdr64[estate.segment].p_offset;
552 iend = istart + estate.p.phdr64[estate.segment].p_filesz;
554 if (!prep_segment(start, mid, end, istart, iend)) {
555 return dead_download;
557 if (!elf_prep_segment(start, mid, end, istart, iend)) {
558 return dead_download;
565 return elf64_download;
568 static sector_t elf64_download(unsigned char *data, unsigned int len, int eof)
570 unsigned long skip_sectors = 0;
571 unsigned int offset; /* working offset in the current data block */
576 if (estate.segment != -1) {
578 if (estate.skip >= len - offset) {
579 estate.skip -= len - offset;
582 offset += estate.skip;
588 cplen = len - offset;
589 if (cplen >= estate.toread) {
590 cplen = estate.toread;
592 memcpy(phys_to_virt(estate.curaddr), data+offset, cplen);
593 estate.curaddr += cplen;
594 estate.toread -= cplen;
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.
607 for (i = 0; i < estate.e.elf64.e_phnum; i++) {
608 if (estate.p.phdr64[i].p_type != PT_LOAD)
610 if (estate.p.phdr64[i].p_filesz == 0)
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 */
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;
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;
630 printf("PHDR %d, size %#lX, curaddr %#lX\n",
631 estate.segment, estate.toread, estate.curaddr);
633 } while (offset < len);
635 estate.loc += len + (estate.skip & ~0x1ff);
636 skip_sectors = estate.skip >> 9;
637 estate.skip &= 0x1ff;
641 unsigned long machine;
643 entry = estate.e.elf64.e_entry;
644 machine = estate.e.elf64.e_machine;
646 if (estate.check_ip_checksum) {
647 unsigned long bytes = 0;
648 uint16_t sum, new_sum;
650 sum = ipchksum(&estate.e.elf64, sizeof(estate.e.elf64));
651 bytes = sizeof(estate.e.elf64);
653 printf("Ehdr: %hx %hx sz: %lx bytes: %lx\n",
654 sum, sum, bytes, bytes);
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;
661 printf("Phdr: %hx %hx sz: %lx bytes: %lx\n",
663 sizeof(estate.p.phdr64[0]) * estate.e.elf64.e_phnum, bytes);
666 for(i = 0; i < estate.e.elf64.e_phnum; i++) {
667 if (estate.p.phdr64[i].p_type != PT_LOAD)
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;
674 printf("seg%d: %hx %hx sz: %x bytes: %lx\n",
676 estate.p.phdr64[i].p_memsz, bytes);
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);
688 /* Fixup the offset to the program header so you can find the program headers from
689 * the ELF header mknbi needs this.
691 estate.e.elf64.e_phoff = (char *)&estate.p - (char *)&estate.e;
692 elf_boot(machine,entry);
697 #endif /* ELF64_IMAGE */