/* %ANU_GPL_License% */ /* $Id: load_elf.cc,v 1.4 2004/11/30 02:06:26 wpc Exp $ * * loading of elf files in "boot from main" mode * /lib 20020225 */ #include // for mode macros (open) #include "sulima/elf_wrapper.hh" #include "sulima/load_elf.hh" #include "sulima/backplane.hh" #include "ute/ref.hh" namespace { void memcpy_to_ram(void* ramv, UInt64 addr, UInt8* from, UInt64 n) { UInt8 *ram = reinterpret_cast(ramv); std::memcpy(ram+addr, from, n); } void memset_to_ram(void* ramv, UInt64 addr, UInt8 val, UInt64 n) { UInt8 *ram = reinterpret_cast(ramv); std::memset(ram+addr, val, n); } } // anonymous namespace namespace Sulima { bool load_elf(const BackplaneRef& bp, const String& filename, bool do_ram_offset, bool *is64_p, UInt64 *entry_pt_p) { //msg("load_elf: %s: loading", filename.c_str()); // check that this is an ELF image file if (elf_version(EV_CURRENT) == EV_NONE) { // elf library out of date //msg("load_elf: library out of date"); return false; } // Open the ELF image file FD::Wrapper fdw(FD::open(filename, O_RDONLY)); if (fdw->fd == -1) { //msg("load_elf: %s: could not open", filename.c_str()); return false; } ELF::Wrapper elf(ELF::open(fdw, ELF_C_READ)); if (!ELF::valid(elf)) { //msg("load_elf: %s: bad ELF", filename.c_str()); return false; } // set is64 to class of file: bool is64 = ELF::is64(elf); //msg("load_elf: %s: is %s-bit", filename.c_str(), is64?"64":"32"); if (is64_p) *is64_p = is64; const UInt64 base = ELF::get_base(elf); if (base == UInt64(-1)) { //msg("load_elf: %s: could not get base", filename.c_str()); return false; } // set the entry_pt: UInt64 entry_pt = ELF::get_entry(elf); if (entry_pt == UInt64(-1)) { //msg("load_elf: %s: could not get entry point", filename.c_str()); return false; } if (entry_pt_p) *entry_pt_p = entry_pt; UInt64 memory_size = 0; void *ram = bp->memory(0, memory_size); // ram_offset is base moved down to a page (8K) if it isn't already: // (this loads the file as low as possible in ram) UInt64 ram_offset; if (do_ram_offset) ram_offset = base & ~UInt64(0x1fff); else ram_offset = 0; printf("load_elf: base=%llx offset=%llx entry=%llx\n", base, ram_offset, entry_pt); UInt64 top = base; int cnt = 1; for (Elf_Scn *scn = elf_nextscn(elf->elf, NULL); scn != NULL; ++cnt, scn = elf_nextscn(elf->elf, scn)) { const UInt64 sh_addr = ELF::get_sh_addr(scn); if (sh_addr == UInt64(-1)) { //msg("load_elf: %s: problem reading section number %d", filename.c_str(), // cnt); continue; } //msg("Section %d, sh_addr 0x%016llx", cnt, sh_addr); if (sh_addr == 0) { // not loadable, skipping continue; } int dcnt = 1; for (Elf_Data *data = elf_getdata(scn, NULL); data != NULL; ++dcnt, data = elf_getdata(scn, data)) { // update top: const UInt64 phys_addr = sh_addr + data->d_off; const UInt64 max_addr = phys_addr + data->d_size; if (max_addr > top) top = max_addr; if (top - ram_offset > memory_size) { //msg("load_elf: %s: not enough memory for executable", filename.c_str()); return false; } const UInt64 off_phys_addr = phys_addr - ram_offset; const UInt32 d_size = data->d_size; UInt8* d_buf = reinterpret_cast(data->d_buf); if (d_buf) { // we have data: copy it to memory // we could look at data->d_align to find out alignment: // note: this only indicates alignment of start of source and the // destination, the length may not be aligned! // we don't do this since it's not necessary. printf("copying section %d to RAM address %llx\n", cnt, off_phys_addr); memcpy_to_ram(ram, off_phys_addr, d_buf, d_size); } else { // !d_buf // we have zero'd data: "memset" it // data->d_size tells us how much there is: see elf_getdata(3E) memset_to_ram(ram, off_phys_addr, 0, d_size); } // zero'd data } // for data } // for scn // at this point, the executable has been loaded, and top has been set to // the largest loaded address // some sanity checks: if ((entry_pt < base) || (entry_pt >= top)) { //msg("load_elf: %s: invalid entry point", filename.c_str()); return false; } // Set up the ram offset (if we've elected to use one) bp->ram_offset() = ram_offset; return true; } // load_ELF() } // namespace Sulima