123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699 |
- #include "elf.h"
-
- #ifndef ELF_CHECK_ARCH
- #error ELF_CHECK_ARCH not defined
- #endif
-
- #define ELF_NOTES 1
- #define ELF_DEBUG 0
-
- struct elf_state
- {
- union {
- Elf32_Ehdr elf32;
- Elf64_Ehdr elf64;
- } e;
- union {
- Elf32_Phdr phdr32[1];
- Elf64_Phdr phdr64[1];
- unsigned char dummy[1024];
- } p;
- unsigned long curaddr;
- int segment; /* current segment number, -1 for none */
- uint64_t loc; /* start offset of current block */
- uint64_t skip; /* padding to be skipped to current segment */
- unsigned long toread; /* remaining data to be read in the segment */
- #if ELF_NOTES
- int check_ip_checksum;
- uint16_t ip_checksum;
- unsigned long ip_checksum_offset;
- #endif
- };
-
- static struct elf_state estate;
-
- static unsigned long find_segment(unsigned long size, unsigned long align)
- {
- unsigned i;
- /* Verify I have a power of 2 alignment */
- if (align & (align - 1)) {
- return ULONG_MAX;
- }
- for(i = 0; i < meminfo.map_count; i++) {
- unsigned long r_start, r_end;
- if (meminfo.map[i].type != E820_RAM)
- continue;
- if ((meminfo.map[i].addr + meminfo.map[i].size) > ULONG_MAX) {
- continue;
- }
- r_start = meminfo.map[i].addr;
- r_end = r_start + meminfo.map[i].size;
- /* Don't allow the segment to overlap etherboot */
- if ((r_end > virt_to_phys(_text)) && (r_start < virt_to_phys(_text))) {
- r_end = virt_to_phys(_text);
- }
- if ((r_start > virt_to_phys(_text)) && (r_start < virt_to_phys(_end))) {
- r_start = virt_to_phys(_end);
- }
- /* Don't allow the segment to overlap the heap */
- if ((r_end > heap_ptr) && (r_start < heap_ptr)) {
- r_end = heap_ptr;
- }
- if ((r_start > heap_ptr) && (r_start < heap_bot)) {
- r_start = heap_ptr;
- }
- r_start = (r_start + align - 1) & ~(align - 1);
- if ((r_end >= r_start) && ((r_end - r_start) >= size)) {
- return r_start;
- }
- }
- /* I did not find anything :( */
- return ULONG_MAX;
- }
-
- static void elf_boot(unsigned long machine, unsigned long entry)
- {
- int result;
- struct Elf_Bhdr *hdr;
- multiboot_boot(entry);
- /* We cleanup unconditionally, and then reawaken the network
- * adapter after the longjmp.
- */
- hdr = prepare_boot_params(&estate.e);
- result = elf_start(machine, entry, virt_to_phys(hdr));
- if (result == 0) {
- result = -1;
- }
- printf("Secondary program returned %d\n", result);
- longjmp(restart_etherboot, result);
- }
-
- #if ELF_NOTES
- static int elf_prep_segment(
- unsigned long start __unused, unsigned long mid __unused, unsigned long end __unused,
- unsigned long istart, unsigned long iend)
-
- {
- if (estate.check_ip_checksum) {
- if ((istart <= estate.ip_checksum_offset) &&
- (iend > estate.ip_checksum_offset)) {
- /* The checksum note is also loaded in a
- * PT_LOAD segment, so the computed checksum
- * should be 0.
- */
- estate.ip_checksum = 0;
- }
- }
- return 1;
- }
- #else
- #define elf_prep_segment(start, mid, end, istart, iend) (1)
- #endif
-
-
- #if ELF_NOTES
- static void process_elf_notes(unsigned char *header,
- unsigned long offset, unsigned long length)
- {
- unsigned char *note, *end;
- char *program, *version;
-
- estate.check_ip_checksum = 0;
- note = header + offset;
- end = note + length;
- program = version = 0;
- while(note < end) {
- Elf_Nhdr *hdr;
- unsigned char *n_name, *n_desc, *next;
- hdr = (Elf_Nhdr *)note;
- n_name = note + sizeof(*hdr);
- n_desc = n_name + ((hdr->n_namesz + 3) & ~3);
- next = n_desc + ((hdr->n_descsz + 3) & ~3);
- if (next > end) {
- break;
- }
- if ((hdr->n_namesz == sizeof(ELF_NOTE_BOOT)) &&
- (memcmp(n_name, ELF_NOTE_BOOT, sizeof(ELF_NOTE_BOOT)) == 0)) {
- switch(hdr->n_type) {
- case EIN_PROGRAM_NAME:
- if (n_desc[hdr->n_descsz -1] == 0) {
- program = n_desc;
- }
- break;
- case EIN_PROGRAM_VERSION:
- if (n_desc[hdr->n_descsz -1] == 0) {
- version = n_desc;
- }
- break;
- case EIN_PROGRAM_CHECKSUM:
- estate.check_ip_checksum = 1;
- estate.ip_checksum = *((uint16_t *)n_desc);
- /* Remember where the segment is so
- * I can detect segment overlaps.
- */
- estate.ip_checksum_offset = n_desc - header;
- #if ELF_DEBUG
- printf("Checksum: %hx\n", estate.ip_checksum);
- #endif
-
- break;
- }
- }
- #if ELF_DEBUG
- printf("n_type: %x n_name(%d): %s n_desc(%d): %s\n",
- hdr->n_type,
- hdr->n_namesz, n_name,
- hdr->n_descsz, n_desc);
- #endif
- note = next;
- }
- if (program && version) {
- printf("\nLoading %s version: %s\n", program, version);
- }
- }
- #endif
-
- #ifdef ELF_IMAGE
- static sector_t elf32_download(unsigned char *data, unsigned int len, int eof);
- static inline os_download_t elf32_probe(unsigned char *data, unsigned int len)
- {
- unsigned long phdr_size;
- if (len < sizeof(estate.e.elf32)) {
- return 0;
- }
- memcpy(&estate.e.elf32, data, sizeof(estate.e.elf32));
- if ((estate.e.elf32.e_ident[EI_MAG0] != ELFMAG0) ||
- (estate.e.elf32.e_ident[EI_MAG1] != ELFMAG1) ||
- (estate.e.elf32.e_ident[EI_MAG2] != ELFMAG2) ||
- (estate.e.elf32.e_ident[EI_MAG3] != ELFMAG3) ||
- (estate.e.elf32.e_ident[EI_CLASS] != ELFCLASS32) ||
- (estate.e.elf32.e_ident[EI_DATA] != ELFDATA_CURRENT) ||
- (estate.e.elf32.e_ident[EI_VERSION] != EV_CURRENT) ||
- ( (estate.e.elf32.e_type != ET_EXEC) &&
- (estate.e.elf32.e_type != ET_DYN)) ||
- (estate.e.elf32.e_version != EV_CURRENT) ||
- (estate.e.elf32.e_ehsize != sizeof(Elf32_Ehdr)) ||
- (estate.e.elf32.e_phentsize != sizeof(Elf32_Phdr)) ||
- !ELF_CHECK_ARCH(estate.e.elf32)) {
- return 0;
- }
- printf("(ELF");
- elf_freebsd_probe();
- printf(")... ");
- phdr_size = estate.e.elf32.e_phnum * estate.e.elf32.e_phentsize;
- if (estate.e.elf32.e_phoff + phdr_size > len) {
- printf("ELF header outside first block\n");
- return dead_download;
- }
- if (phdr_size > sizeof(estate.p.dummy)) {
- printf("Program header too big\n");
- return dead_download;
- }
- memcpy(&estate.p.phdr32, data + estate.e.elf32.e_phoff, phdr_size);
- if (estate.e.elf32.e_type == ET_DYN) {
- Elf32_Addr min, max, base_addr, delta, align;
- min = -1;
- max = 0;
- align = 1;
- for(estate.segment = 0; estate.segment < estate.e.elf32.e_phnum; estate.segment++) {
- Elf32_Addr val;
- if (estate.p.phdr32[estate.segment].p_type != PT_LOAD)
- continue;
- val = estate.p.phdr32[estate.segment].p_paddr;
- if (val < min) {
- min = val;
- }
- val += estate.p.phdr32[estate.segment].p_memsz;
- if (val > max) {
- max = val;
- }
- if (estate.p.phdr32[estate.segment].p_align > align) {
- align = estate.p.phdr32[estate.segment].p_align;
- }
- }
- if (align & (align -1)) {
- printf("ELF base address alignment is not a power of 2\n");
- return dead_download;
- }
- base_addr = find_segment(max - min, align);
- if (base_addr == ULONG_MAX) {
- printf("ELF base address not available for size %ld\n", max - min);
- return dead_download;
- }
- /* Compute the change in base address and fix up the addresses */
- delta = base_addr - min;
- for(estate.segment = 0; estate.segment < estate.e.elf32.e_phnum; estate.segment++) {
- /* Change the base address of the object to load */
- estate.p.phdr32[estate.segment].p_paddr += delta;
- }
- estate.e.elf32.e_entry += delta;
- }
- #if ELF_NOTES
- /* Load ELF notes from the image */
- estate.check_ip_checksum = 0;
- for(estate.segment = 0; estate.segment < estate.e.elf32.e_phnum; estate.segment++) {
- if (estate.p.phdr32[estate.segment].p_type != PT_NOTE)
- continue;
- if (estate.p.phdr32[estate.segment].p_offset + estate.p.phdr32[estate.segment].p_filesz > len) {
- /* Ignore ELF notes outside of the first block */
- continue;
- }
- process_elf_notes(data,
- estate.p.phdr32[estate.segment].p_offset, estate.p.phdr32[estate.segment].p_filesz);
- }
- #endif
- /* Check for Etherboot related limitations. Memory
- * between _text and _end is not allowed.
- * Reasons: the Etherboot code/data area.
- */
- for (estate.segment = 0; estate.segment < estate.e.elf32.e_phnum; estate.segment++) {
- unsigned long start, mid, end, istart, iend;
- if (estate.p.phdr32[estate.segment].p_type != PT_LOAD)
- continue;
-
- elf_freebsd_fixup_segment();
-
- start = estate.p.phdr32[estate.segment].p_paddr;
- mid = start + estate.p.phdr32[estate.segment].p_filesz;
- end = start + estate.p.phdr32[estate.segment].p_memsz;
- istart = estate.p.phdr32[estate.segment].p_offset;
- iend = istart + estate.p.phdr32[estate.segment].p_filesz;
- if (!prep_segment(start, mid, end, istart, iend)) {
- return dead_download;
- }
- if (!elf_prep_segment(start, mid, end, istart, iend)) {
- return dead_download;
- }
- }
- estate.segment = -1;
- estate.loc = 0;
- estate.skip = 0;
- estate.toread = 0;
- multiboot_init();
- return elf32_download;
- }
-
- static sector_t elf32_download(unsigned char *data, unsigned int len, int eof)
- {
- unsigned long skip_sectors = 0;
- unsigned int offset; /* working offset in the current data block */
- int i;
-
- offset = 0;
- do {
- if (estate.segment != -1) {
- if (estate.skip) {
- if (estate.skip >= len - offset) {
- estate.skip -= len - offset;
- break;
- }
- offset += estate.skip;
- estate.skip = 0;
- }
-
- if (estate.toread) {
- unsigned int cplen;
- cplen = len - offset;
- if (cplen >= estate.toread) {
- cplen = estate.toread;
- }
- memcpy(phys_to_virt(estate.curaddr), data+offset, cplen);
- estate.curaddr += cplen;
- estate.toread -= cplen;
- offset += cplen;
- if (estate.toread)
- break;
- elf_freebsd_find_segment_end();
- }
- }
-
- /* Data left, but current segment finished - look for the next
- * segment (in file offset order) that needs to be loaded.
- * We can only seek forward, so select the program headers,
- * in the correct order.
- */
- estate.segment = -1;
- for (i = 0; i < estate.e.elf32.e_phnum; i++) {
- if (estate.p.phdr32[i].p_type != PT_LOAD)
- continue;
- if (estate.p.phdr32[i].p_filesz == 0)
- continue;
- if (estate.p.phdr32[i].p_offset < estate.loc + offset)
- continue; /* can't go backwards */
- if ((estate.segment != -1) &&
- (estate.p.phdr32[i].p_offset >= estate.p.phdr32[estate.segment].p_offset))
- continue; /* search minimum file offset */
- estate.segment = i;
- }
- if (estate.segment == -1) {
- if (elf_freebsd_debug_loader(offset)) {
- estate.segment = 0; /* -1 makes it not read anymore */
- continue;
- }
- /* No more segments to be loaded, so just start the
- * kernel. This saves a lot of network bandwidth if
- * debug info is in the kernel but not loaded. */
- goto elf_startkernel;
- break;
- }
- estate.curaddr = estate.p.phdr32[estate.segment].p_paddr;
- estate.skip = estate.p.phdr32[estate.segment].p_offset - (estate.loc + offset);
- estate.toread = estate.p.phdr32[estate.segment].p_filesz;
- #if ELF_DEBUG
- printf("PHDR %d, size %#lX, curaddr %#lX\n",
- estate.segment, estate.toread, estate.curaddr);
- #endif
- } while (offset < len);
-
- estate.loc += len + (estate.skip & ~0x1ff);
- skip_sectors = estate.skip >> 9;
- estate.skip &= 0x1ff;
-
- if (eof) {
- unsigned long entry;
- unsigned long machine;
- elf_startkernel:
- entry = estate.e.elf32.e_entry;
- machine = estate.e.elf32.e_machine;
-
- #if ELF_NOTES
- if (estate.check_ip_checksum) {
- unsigned long bytes = 0;
- uint16_t sum, new_sum;
-
- sum = ipchksum(&estate.e.elf32, sizeof(estate.e.elf32));
- bytes = sizeof(estate.e.elf32);
- #if ELF_DEBUG
- printf("Ehdr: %hx %hx sz: %lx bytes: %lx\n",
- sum, sum, bytes, bytes);
- #endif
-
- new_sum = ipchksum(estate.p.phdr32, sizeof(estate.p.phdr32[0]) * estate.e.elf32.e_phnum);
- sum = add_ipchksums(bytes, sum, new_sum);
- bytes += sizeof(estate.p.phdr32[0]) * estate.e.elf32.e_phnum;
- #if ELF_DEBUG
- printf("Phdr: %hx %hx sz: %lx bytes: %lx\n",
- new_sum, sum,
- sizeof(estate.p.phdr32[0]) * estate.e.elf32.e_phnum, bytes);
- #endif
-
- for(i = 0; i < estate.e.elf32.e_phnum; i++) {
- if (estate.p.phdr32[i].p_type != PT_LOAD)
- continue;
- new_sum = ipchksum(phys_to_virt(estate.p.phdr32[i].p_paddr),
- estate.p.phdr32[i].p_memsz);
- sum = add_ipchksums(bytes, sum, new_sum);
- bytes += estate.p.phdr32[i].p_memsz;
- #if ELF_DEBUG
- printf("seg%d: %hx %hx sz: %x bytes: %lx\n",
- i, new_sum, sum,
- estate.p.phdr32[i].p_memsz, bytes);
- #endif
-
- }
- if (estate.ip_checksum != sum) {
- printf("\nImage checksum: %hx != computed checksum: %hx\n",
- estate.ip_checksum, sum);
- longjmp(restart_etherboot, -2);
- }
- }
- #endif
- done(1);
- /* Fixup the offset to the program header so you can find the program headers from
- * the ELF header mknbi needs this.
- */
- estate.e.elf32.e_phoff = (char *)&estate.p - (char *)&estate.e;
- elf_freebsd_boot(entry);
- elf_boot(machine,entry);
- }
- return skip_sectors;
- }
- #endif /* ELF_IMAGE */
-
- #ifdef ELF64_IMAGE
- static sector_t elf64_download(unsigned char *data, unsigned int len, int eof);
- static inline os_download_t elf64_probe(unsigned char *data, unsigned int len)
- {
- unsigned long phdr_size;
- if (len < sizeof(estate.e.elf64)) {
- return 0;
- }
- memcpy(&estate.e.elf64, data, sizeof(estate.e.elf64));
- if ((estate.e.elf64.e_ident[EI_MAG0] != ELFMAG0) ||
- (estate.e.elf64.e_ident[EI_MAG1] != ELFMAG1) ||
- (estate.e.elf64.e_ident[EI_MAG2] != ELFMAG2) ||
- (estate.e.elf64.e_ident[EI_MAG3] != ELFMAG3) ||
- (estate.e.elf64.e_ident[EI_CLASS] != ELFCLASS64) ||
- (estate.e.elf64.e_ident[EI_DATA] != ELFDATA_CURRENT) ||
- (estate.e.elf64.e_ident[EI_VERSION] != EV_CURRENT) ||
- ( (estate.e.elf64.e_type != ET_EXEC) &&
- (estate.e.elf64.e_type != ET_DYN)) ||
- (estate.e.elf64.e_version != EV_CURRENT) ||
- (estate.e.elf64.e_ehsize != sizeof(Elf64_Ehdr)) ||
- (estate.e.elf64.e_phentsize != sizeof(Elf64_Phdr)) ||
- !ELF_CHECK_ARCH(estate.e.elf64)) {
- return 0;
- }
- printf("(ELF64)... ");
- phdr_size = estate.e.elf64.e_phnum * estate.e.elf64.e_phentsize;
- if (estate.e.elf64.e_phoff + phdr_size > len) {
- printf("ELF header outside first block\n");
- return dead_download;
- }
- if (phdr_size > sizeof(estate.p.dummy)) {
- printf("Program header to big\n");
- return dead_download;
- }
- if (estate.e.elf64.e_entry > ULONG_MAX) {
- printf("ELF entry point exceeds address space\n");
- return dead_download;
- }
- memcpy(&estate.p.phdr64, data + estate.e.elf64.e_phoff, phdr_size);
- if (estate.e.elf64.e_type == ET_DYN) {
- Elf64_Addr min, max, base_addr, delta, align;
- min = -1;
- max = 0;
- align = 1;
- for(estate.segment = 0; estate.segment < estate.e.elf64.e_phnum; estate.segment++) {
- Elf64_Addr val;
- if (estate.p.phdr64[estate.segment].p_type != PT_LOAD)
- continue;
- val = estate.p.phdr64[estate.segment].p_paddr;
- if (val < min) {
- min = val;
- }
- val += estate.p.phdr64[estate.segment].p_memsz;
- if (val > max) {
- max = val;
- }
- if (estate.p.phdr64[estate.segment].p_align > align) {
- align = estate.p.phdr64[estate.segment].p_align;
- }
- }
- if (align > ULONG_MAX) {
- printf("ELF base address alignment exceeds address space\n");
- return dead_download;
- }
- if (align & (align -1)) {
- printf("ELF base address alignment is not a power of 2\n");
- return dead_download;
- }
- if ((max - min) > ULONG_MAX) {
- printf("ELF size exceeds address space\n");
- return dead_download;
- }
- base_addr = find_segment(max - min, align);
- if (base_addr == ULONG_MAX) {
- printf("ELF base address not available for size %ld\n", max - min);
- return dead_download;
- }
- /* Compute the change in base address and fix up the addresses */
- delta = base_addr - min;
- for(estate.segment = 0; estate.segment < estate.e.elf64.e_phnum; estate.segment++) {
- /* Change the base address of the object to load */
- estate.p.phdr64[estate.segment].p_paddr += delta;
- }
- estate.e.elf64.e_entry += delta;
- }
- #if ELF_NOTES
- /* Load ELF notes from the image */
- estate.check_ip_checksum = 0;
- for(estate.segment = 0; estate.segment < estate.e.elf64.e_phnum; estate.segment++) {
- if (estate.p.phdr64[estate.segment].p_type != PT_NOTE)
- continue;
- if (estate.p.phdr64[estate.segment].p_offset + estate.p.phdr64[estate.segment].p_filesz > len) {
- /* Ignore ELF notes outside of the first block */
- continue;
- }
- process_elf_notes(data,
- estate.p.phdr64[estate.segment].p_offset, estate.p.phdr64[estate.segment].p_filesz);
- }
- #endif
- /* Check for Etherboot related limitations. Memory
- * between _text and _end is not allowed.
- * Reasons: the Etherboot code/data area.
- */
- for (estate.segment = 0; estate.segment < estate.e.elf64.e_phnum; estate.segment++) {
- unsigned long start, mid, end, istart, iend;
- if (estate.p.phdr64[estate.segment].p_type != PT_LOAD)
- continue;
- if ((estate.p.phdr64[estate.segment].p_paddr > ULONG_MAX) ||
- ((estate.p.phdr64[estate.segment].p_paddr + estate.p.phdr64[estate.segment].p_filesz) > ULONG_MAX) ||
- ((estate.p.phdr64[estate.segment].p_paddr + estate.p.phdr64[estate.segment].p_memsz) > ULONG_MAX)) {
- printf("ELF segment exceeds address space\n");
- return dead_download;
- }
- start = estate.p.phdr64[estate.segment].p_paddr;
- mid = start + estate.p.phdr64[estate.segment].p_filesz;
- end = start + estate.p.phdr64[estate.segment].p_memsz;
- istart = iend = ULONG_MAX;
- if ((estate.p.phdr64[estate.segment].p_offset < ULONG_MAX) &&
- ((estate.p.phdr64[estate.segment].p_offset + estate.p.phdr64[estate.segment].p_filesz) < ULONG_MAX))
- {
- istart = estate.p.phdr64[estate.segment].p_offset;
- iend = istart + estate.p.phdr64[estate.segment].p_filesz;
- }
- if (!prep_segment(start, mid, end, istart, iend)) {
- return dead_download;
- }
- if (!elf_prep_segment(start, mid, end, istart, iend)) {
- return dead_download;
- }
- }
- estate.segment = -1;
- estate.loc = 0;
- estate.skip = 0;
- estate.toread = 0;
- return elf64_download;
- }
-
- static sector_t elf64_download(unsigned char *data, unsigned int len, int eof)
- {
- unsigned long skip_sectors = 0;
- unsigned int offset; /* working offset in the current data block */
- int i;
-
- offset = 0;
- do {
- if (estate.segment != -1) {
- if (estate.skip) {
- if (estate.skip >= len - offset) {
- estate.skip -= len - offset;
- break;
- }
- offset += estate.skip;
- estate.skip = 0;
- }
-
- if (estate.toread) {
- unsigned int cplen;
- cplen = len - offset;
- if (cplen >= estate.toread) {
- cplen = estate.toread;
- }
- memcpy(phys_to_virt(estate.curaddr), data+offset, cplen);
- estate.curaddr += cplen;
- estate.toread -= cplen;
- offset += cplen;
- if (estate.toread)
- break;
- }
- }
-
- /* Data left, but current segment finished - look for the next
- * segment (in file offset order) that needs to be loaded.
- * We can only seek forward, so select the program headers,
- * in the correct order.
- */
- estate.segment = -1;
- for (i = 0; i < estate.e.elf64.e_phnum; i++) {
- if (estate.p.phdr64[i].p_type != PT_LOAD)
- continue;
- if (estate.p.phdr64[i].p_filesz == 0)
- continue;
- if (estate.p.phdr64[i].p_offset < estate.loc + offset)
- continue; /* can't go backwards */
- if ((estate.segment != -1) &&
- (estate.p.phdr64[i].p_offset >= estate.p.phdr64[estate.segment].p_offset))
- continue; /* search minimum file offset */
- estate.segment = i;
- }
- if (estate.segment == -1) {
- /* No more segments to be loaded, so just start the
- * kernel. This saves a lot of network bandwidth if
- * debug info is in the kernel but not loaded. */
- goto elf_startkernel;
- break;
- }
- estate.curaddr = estate.p.phdr64[estate.segment].p_paddr;
- estate.skip = estate.p.phdr64[estate.segment].p_offset - (estate.loc + offset);
- estate.toread = estate.p.phdr64[estate.segment].p_filesz;
- #if ELF_DEBUG
- printf("PHDR %d, size %#lX, curaddr %#lX\n",
- estate.segment, estate.toread, estate.curaddr);
- #endif
- } while (offset < len);
-
- estate.loc += len + (estate.skip & ~0x1ff);
- skip_sectors = estate.skip >> 9;
- estate.skip &= 0x1ff;
-
- if (eof) {
- unsigned long entry;
- unsigned long machine;
- elf_startkernel:
- entry = estate.e.elf64.e_entry;
- machine = estate.e.elf64.e_machine;
- #if ELF_NOTES
- if (estate.check_ip_checksum) {
- unsigned long bytes = 0;
- uint16_t sum, new_sum;
-
- sum = ipchksum(&estate.e.elf64, sizeof(estate.e.elf64));
- bytes = sizeof(estate.e.elf64);
- #if ELF_DEBUG
- printf("Ehdr: %hx %hx sz: %lx bytes: %lx\n",
- sum, sum, bytes, bytes);
- #endif
-
- new_sum = ipchksum(estate.p.phdr64, sizeof(estate.p.phdr64[0]) * estate.e.elf64.e_phnum);
- sum = add_ipchksums(bytes, sum, new_sum);
- bytes += sizeof(estate.p.phdr64[0]) * estate.e.elf64.e_phnum;
- #if ELF_DEBUG
- printf("Phdr: %hx %hx sz: %lx bytes: %lx\n",
- new_sum, sum,
- sizeof(estate.p.phdr64[0]) * estate.e.elf64.e_phnum, bytes);
- #endif
-
- for(i = 0; i < estate.e.elf64.e_phnum; i++) {
- if (estate.p.phdr64[i].p_type != PT_LOAD)
- continue;
- new_sum = ipchksum(phys_to_virt(estate.p.phdr64[i].p_paddr),
- estate.p.phdr64[i].p_memsz);
- sum = add_ipchksums(bytes, sum, new_sum);
- bytes += estate.p.phdr64[i].p_memsz;
- #if ELF_DEBUG
- printf("seg%d: %hx %hx sz: %x bytes: %lx\n",
- i, new_sum, sum,
- estate.p.phdr64[i].p_memsz, bytes);
- #endif
-
- }
- if (estate.ip_checksum != sum) {
- printf("\nImage checksum: %hx != computed checksum: %hx\n",
- estate.ip_checksum, sum);
- longjmp(restart_etherboot, -2);
- }
- }
- #endif
- done(1);
- /* Fixup the offset to the program header so you can find the program headers from
- * the ELF header mknbi needs this.
- */
- estate.e.elf64.e_phoff = (char *)&estate.p - (char *)&estate.e;
- elf_boot(machine,entry);
- }
- return skip_sectors;
- }
-
- #endif /* ELF64_IMAGE */
|