char* elf_rawfile(Elf *elf, size_t *ptr) { size_t tmp; if (!ptr) { ptr = &tmp; } *ptr = 0; if (!elf) { return NULL; } elf_assert(elf->e_magic == ELF_MAGIC); if (!elf->e_readable) { return NULL; } else if (elf->e_size && !elf->e_rawdata) { elf_assert(elf->e_data); if (!elf->e_cooked) { elf->e_rawdata = elf->e_data; } else if (!(elf->e_rawdata = _elf_read(elf, NULL, 0, elf->e_size))) { return NULL; } *ptr = elf->e_size; } return elf->e_rawdata; }
char * elf_rawfile(Elf * elf, size_t * ptr) { register size_t sz; char *p = 0; if (elf == 0) { if (ptr != 0) *ptr = 0; return (0); } ELFWLOCK(elf) if ((sz = elf->ed_fsz) == 0) { if (ptr != 0) *ptr = 0; ELFUNLOCK(elf) return (0); } if (elf->ed_raw != 0) p = elf->ed_raw; else if (elf->ed_status == ES_COOKED) { if ((p = _elf_read(elf->ed_fd, elf->ed_baseoff, sz)) != 0) { elf->ed_raw = p; elf->ed_myflags |= EDF_RAWALLOC; } else sz = 0; } else { p = elf->ed_raw = elf->ed_ident; elf->ed_status = ES_FROZEN; if (_elf_vm(elf, (size_t)0, elf->ed_fsz) != OK_YES) { p = 0; sz = 0; } } if (ptr != 0) *ptr = sz; ELFUNLOCK(elf) return (p); }
Elf_Data* elf_rawdata(Elf_Scn *scn, Elf_Data *data) { Scn_Data *sd; Elf *elf; if (!scn) { return NULL; } elf_assert(scn->s_magic == SCN_MAGIC); elf = scn->s_elf; elf_assert(elf); elf_assert(elf->e_magic == ELF_MAGIC); if (!elf->e_readable) { return NULL; } else if (scn->s_index == SHN_UNDEF || scn->s_type == SHT_NULL) { seterr(ERROR_NULLSCN); } else if (data) { return NULL; } else if ((sd = scn->s_rawdata)) { return &sd->sd_data; } else if (scn->s_offset < 0 || scn->s_offset > elf->e_size) { seterr(ERROR_OUTSIDE); } else if (scn->s_type != SHT_NOBITS && scn->s_offset + scn->s_size > elf->e_size) { seterr(ERROR_TRUNC_SCN); } else if (!(sd = (Scn_Data*)malloc(sizeof(*sd)))) { seterr(ERROR_MEM_SCNDATA); } else { *sd = _elf_data_init; sd->sd_freeme = 1; sd->sd_data.d_size = scn->s_size; sd->sd_data.d_version = _elf_version; if (scn->s_type != SHT_NOBITS && scn->s_size) { if (!(sd->sd_memdata = (char*)malloc(scn->s_size))) { seterr(ERROR_IO_2BIG); free(sd); return NULL; } else if (elf->e_rawdata) { memcpy(sd->sd_memdata, elf->e_rawdata + scn->s_offset, scn->s_size); } else if (!_elf_read(elf, sd->sd_memdata, scn->s_offset, scn->s_size)) { free(sd->sd_memdata); free(sd); return NULL; } sd->sd_data.d_buf = sd->sd_memdata; sd->sd_free_data = 1; } scn->s_rawdata = sd; return &sd->sd_data; } return NULL; }
Elf* elf_begin(int fd, Elf_Cmd cmd, Elf *ref) { Elf_Arhdr *arhdr = NULL; size_t size = 0; off_t off; Elf *elf; elf_assert(_elf_init.e_magic == ELF_MAGIC); if (_elf_version == EV_NONE) { seterr(ERROR_VERSION_UNSET); return NULL; } else if (cmd == ELF_C_NULL) { return NULL; } else if (cmd == ELF_C_WRITE) { ref = NULL; } else if (cmd != ELF_C_READ && cmd != ELF_C_RDWR) { seterr(ERROR_INVALID_CMD); return NULL; } else if (ref) { elf_assert(ref->e_magic == ELF_MAGIC); if (!ref->e_readable || (cmd == ELF_C_RDWR && !ref->e_writable)) { seterr(ERROR_CMDMISMATCH); return NULL; } if (ref->e_kind != ELF_K_AR) { ref->e_count++; return ref; } if (cmd == ELF_C_RDWR) { seterr(ERROR_MEMBERWRITE); return NULL; } if (ref->e_memory) { fd = ref->e_fd; } else if (fd != ref->e_fd) { seterr(ERROR_FDMISMATCH); return NULL; } if (!(arhdr = _elf_arhdr(ref))) { return NULL; } size = arhdr->ar_size; } else if ((off = lseek(fd, (off_t)0, SEEK_END)) == (off_t)-1 // Cause assert! || (off_t)(size = off) != off) { seterr(ERROR_IO_GETSIZE); return NULL; } if (!(elf = (Elf*)malloc(sizeof(Elf)))) { seterr(ERROR_MEM_ELF); return NULL; } *elf = _elf_init; elf->e_fd = fd; elf->e_parent = ref; elf->e_size = elf->e_dsize = size; if (cmd != ELF_C_READ) { elf->e_writable = 1; } if (cmd != ELF_C_WRITE) { elf->e_readable = 1; } else { return elf; } if (ref) { size_t offset = ref->e_off + sizeof(struct ar_hdr); Elf *xelf; elf_assert(arhdr); elf->e_arhdr = arhdr; elf->e_base = ref->e_base + offset; /* * Share the archive's memory image. To avoid * multiple independent elf descriptors if the * same member is requested twice, scan the list * of open members for duplicates. * * I don't know how SVR4 handles this case. Don't rely on it. */ for (xelf = ref->e_members; xelf; xelf = xelf->e_link) { elf_assert(xelf->e_parent == ref); if (xelf->e_base == elf->e_base) { free(arhdr); free(elf); xelf->e_count++; return xelf; } } if (size == 0) { elf->e_data = NULL; } #if 1 else { /* * Archive members may be misaligned. Freezing them will * cause libelf to allocate buffers for translated data, * which should be properly aligned in all cases. */ elf_assert(!ref->e_cooked); elf->e_data = elf->e_rawdata = ref->e_data + offset; } #else else if (ref->e_data == ref->e_rawdata) { elf_assert(!ref->e_cooked); /* * archive is frozen - freeze member, too */ elf->e_data = elf->e_rawdata = ref->e_data + offset; } else { elf_assert(!ref->e_memory); elf->e_data = ref->e_data + offset; /* * The member's memory image may have been modified if * the member has been processed before. Since we need the * original image, we have to re-read the archive file. * Will fail if the archive's file descriptor is disabled. */ if (!ref->e_cooked) { ref->e_cooked = 1; } else if (!_elf_read(ref, elf->e_data, offset, size)) { free(arhdr); free(elf); return NULL; } } #endif elf->e_next = offset + size + (size & 1); elf->e_disabled = ref->e_disabled; elf->e_memory = ref->e_memory; /* parent/child linking */ elf->e_link = ref->e_members; ref->e_members = elf; ref->e_count++; /* Slowaris compatibility - do not rely on this! */ ref->e_off = elf->e_next; }
/*-------------------------------------------- | Name: _tiny_elfloader | Description: | Parameters: none | Return Type: none | Comments: | See: ----------------------------------------------*/ unsigned long _tiny_elfloader(unsigned long flash_base, unsigned long base) { Elf32_Ehdr ehdr; Elf32_Phdr phdr[MAX_PHDR]; unsigned long offset = 0; int phx=0; int len=0; unsigned char ch; unsigned char *addr; unsigned long addr_offset = 0; unsigned long highest_address = 0; unsigned long lowest_address = 0xFFFFFFFF; unsigned char *SHORT_DATA = "error: short data reading elf file\r\n"; // int cb=0; boot_handler_t boot_handler = (boot_handler_t)0x00000000; #ifdef DEBUG _elf_printf("read elf file at 0x%x\r\n", (unsigned int)flash_base); #endif //ALREADY DONE //_at91sam9261_remap_internal_ram(); // Read the header _elf_printf("read elf header informations:\r\n" ); if (_elf_read(flash_base, (unsigned char *)&ehdr, sizeof(ehdr)) != sizeof(ehdr)) { #ifdef DEBUG _elf_printf("error: can't read elf header\r\n"); #endif return 0; } offset += sizeof(ehdr); // #ifdef DEBUG _elf_printf( "type: %d, machine: %d, version: %d\r\nentry: 0x%x, PHoff: 0x%x/%d/%d, SHoff: 0x%x/%d/%d\r\n\r\n", ehdr.e_type, ehdr.e_machine, ehdr.e_version, ehdr.e_entry, ehdr.e_phoff, ehdr.e_phentsize, ehdr.e_phnum, ehdr.e_shoff, ehdr.e_shentsize, ehdr.e_shnum); #endif // if (ehdr.e_type != ET_EXEC) { #ifdef DEBUG _elf_printf("error: only absolute elf images supported\r\n"); #endif return 0; } // if (ehdr.e_phnum > MAX_PHDR) { #ifdef DEBUG _elf_printf("error: too many firmware headers\r\n"); #endif return 0; } #ifdef DEBUG _elf_printf("jump to offset 0x%x wait some seconds... ",ehdr.e_phoff); #endif //jump to offset #ifdef USE_OPTIMIZED_READELF //optimized code #if !defined(__GNUC__) _elf_lseek(flash_base,ehdr.e_phoff,0); offset+=ehdr.e_phoff; #endif #else //not optimized original code from reboot while (offset < ehdr.e_phoff) { if (_elf_getc(flash_base) < 0) { #ifdef DEBUG printf(SHORT_DATA); #endif return 0; } offset++; } #endif // #ifdef DEBUG _elf_printf("done\r\n"); #endif #ifdef DEBUG _elf_printf("read elf section header\r\n"); #endif // for (phx = 0; phx < ehdr.e_phnum; phx++) { if (_elf_read(flash_base, (unsigned char *)&phdr[phx], sizeof(phdr[0])) != sizeof(phdr[0])) { #ifdef DEBUG _elf_printf("error: can't read ELF program header\r\n"); #endif return 0; } #ifdef DEBUG _elf_printf( "section header: type: %d, off: 0x%x\r\nva: 0x%x, pa: 0x%x, len: %d/%d, flags: %d\r\n", phdr[phx].p_type, phdr[phx].p_offset, phdr[phx].p_vaddr, phdr[phx].p_paddr, phdr[phx].p_filesz, phdr[phx].p_memsz, phdr[phx].p_flags); #endif offset += sizeof(phdr[0]); } if (base) { // Set address offset based on lowest address in file. addr_offset = 0xFFFFFFFF; for (phx = 0; phx < ehdr.e_phnum; phx++) { #ifdef CYGOPT_REDBOOT_ELF_VIRTUAL_ADDRESS if ((phdr[phx].p_type == PT_LOAD) && (phdr[phx].p_vaddr < addr_offset)) { addr_offset = phdr[phx].p_vaddr; #else if ((phdr[phx].p_type == PT_LOAD) && (phdr[phx].p_paddr < addr_offset)) { addr_offset = phdr[phx].p_paddr; #endif } } addr_offset = (unsigned long)base - addr_offset; }else{ addr_offset = 0; } //phlb modif #if !defined(__GNUC__) _elf_lseek(flash_base,sizeof(ehdr),0); #endif #ifdef DEBUG _elf_printf("copy firmware in ram started:\r\n"); #endif for (phx = 0; phx < ehdr.e_phnum; phx++) { // if (phdr[phx].p_type == PT_LOAD) { // Loadable segment #ifdef CYGOPT_REDBOOT_ELF_VIRTUAL_ADDRESS addr = (unsigned char *)phdr[phx].p_vaddr; #else addr = (unsigned char *)phdr[phx].p_paddr; #endif // len = phdr[phx].p_filesz; if ((unsigned long)addr < lowest_address) { lowest_address = (unsigned long)addr; } // addr += addr_offset; if (offset > phdr[phx].p_offset) { /* if ((phdr[phx].p_offset + len) < offset) { printf("Can't load ELF file - program headers out of order\r\n"); return 0; } */ /*addr += offset - phdr[phx].p_offset;*/ } else { while (offset < phdr[phx].p_offset) { if (_elf_getc(flash_base) < 0) { #ifdef DEBUG printf(SHORT_DATA); #endif return 0; } offset++; } } #ifdef DEBUG _elf_printf( "program header: type: %d, off: 0x%x, va: 0x%x, pa:0x%x, len: %d/%d, flags: %d\r\n", phdr[phx].p_type, phdr[phx].p_offset, phdr[phx].p_vaddr, phdr[phx].p_paddr, phdr[phx].p_filesz, phdr[phx].p_memsz, phdr[phx].p_flags); #endif // Copy data into memory #ifndef USE_OPTIMIZED_READELF while (len-- > 0) { if ((ch = _elf_getc(flash_base)) < 0) { #ifdef DEBUG printf(SHORT_DATA); #endif return 0; } #ifdef CYGSEM_REDBOOT_VALIDATE_USER_RAM_LOADS if (valid_address(addr)) #endif *addr = ch; //original code #ifdef DEBUG if(!(((unsigned long)offset)%(80*1*1024))) _elf_printf("."); #endif addr++; offset++; if ((unsigned long)(addr-addr_offset) > highest_address) { highest_address = (unsigned long)(addr - addr_offset); } } #endif #ifdef USE_OPTIMIZED_READELF // #if defined(__GNUC__) _elf_lseek(flash_base,phdr[phx].p_offset,0); _elf_printf("offset:%d addr:0x%x fl_offset:%d\r\n", offset, addr, elf_flash_offset); #endif cb=0; while((len-cb)) { unsigned char elf_buffer[4096]={0}; int sz=0; if((len-cb)>=sizeof(elf_buffer)) sz=sizeof(elf_buffer); else sz=(len-cb); //cb += read(fd,elf_buffer,sz); cb+=_elf_read(flash_base, addr, sz); /* #ifdef DEBUG lseek(fd_bin,(unsigned long)addr,SEEK_SET); write(fd_bin,elf_buffer,sz); #endif */ #ifdef CYGSEM_REDBOOT_VALIDATE_USER_RAM_LOADS if (valid_address(addr)) #endif //memcpy(addr,elf_buffer,sz); // addr+=sz; offset+=sz; if ((unsigned long)(addr-addr_offset) > highest_address) { highest_address = (unsigned long)(addr - addr_offset); } } #endif } } // Save load base/top and entry if (base) { load_address = base; load_address_end = base + (highest_address - lowest_address); entry_address = base + (ehdr.e_entry - lowest_address); } else { load_address = lowest_address; load_address_end = highest_address; entry_address = ehdr.e_entry; } // nak everything to stop the transfer, since redboot // usually doesn't read all the way to the end of the // elf files. #ifdef DEBUG _elf_printf("\r\ncopy firmware in ram done\r\n"); if (addr_offset) _elf_printf("address offset = 0x%x\n", addr_offset); _elf_printf("firmware entry point: 0x%x, address range: 0x%x-0x%x\r\n",entry_address, load_address, load_address_end); _elf_printf("ready to rumble? ;)\r\nboot on firmware\r\n"); #endif boot_handler = (boot_handler_t)entry_address; //boot!!!! boot_handler(); __asm__("nop"); __asm__("nop"); __asm__("nop"); __asm__("nop"); __asm__("nop"); __asm__("nop"); for(;; ) ; return 1; }