|
|
1.1 ! root 1: /* ! 2: * Copyright (C) 2007 Michael Brown <[email protected]>. ! 3: * ! 4: * This program is free software; you can redistribute it and/or ! 5: * modify it under the terms of the GNU General Public License as ! 6: * published by the Free Software Foundation; either version 2 of the ! 7: * License, or any later version. ! 8: * ! 9: * This program is distributed in the hope that it will be useful, but ! 10: * WITHOUT ANY WARRANTY; without even the implied warranty of ! 11: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ! 12: * General Public License for more details. ! 13: * ! 14: * You should have received a copy of the GNU General Public License ! 15: * along with this program; if not, write to the Free Software ! 16: * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ! 17: */ ! 18: ! 19: FILE_LICENCE ( GPL2_OR_LATER ); ! 20: ! 21: /** ! 22: * @file ! 23: * ! 24: * ELF image format ! 25: * ! 26: * A "pure" ELF image is not a bootable image. There are various ! 27: * bootable formats based upon ELF (e.g. Multiboot), which share ! 28: * common ELF-related functionality. ! 29: */ ! 30: ! 31: #include <errno.h> ! 32: #include <elf.h> ! 33: #include <ipxe/uaccess.h> ! 34: #include <ipxe/segment.h> ! 35: #include <ipxe/image.h> ! 36: #include <ipxe/elf.h> ! 37: ! 38: typedef Elf32_Ehdr Elf_Ehdr; ! 39: typedef Elf32_Phdr Elf_Phdr; ! 40: typedef Elf32_Off Elf_Off; ! 41: ! 42: /** ! 43: * Load ELF segment into memory ! 44: * ! 45: * @v image ELF file ! 46: * @v phdr ELF program header ! 47: * @v ehdr ELF executable header ! 48: * @ret entry Entry point, if found ! 49: * @ret rc Return status code ! 50: */ ! 51: static int elf_load_segment ( struct image *image, Elf_Phdr *phdr, ! 52: Elf_Ehdr *ehdr, physaddr_t *entry ) { ! 53: physaddr_t dest; ! 54: userptr_t buffer; ! 55: unsigned long e_offset; ! 56: int rc; ! 57: ! 58: /* Do nothing for non-PT_LOAD segments */ ! 59: if ( phdr->p_type != PT_LOAD ) ! 60: return 0; ! 61: ! 62: /* Check segment lies within image */ ! 63: if ( ( phdr->p_offset + phdr->p_filesz ) > image->len ) { ! 64: DBGC ( image, "ELF %p segment outside image\n", image ); ! 65: return -ENOEXEC; ! 66: } ! 67: ! 68: /* Find start address: use physical address for preference, ! 69: * fall back to virtual address if no physical address ! 70: * supplied. ! 71: */ ! 72: dest = phdr->p_paddr; ! 73: if ( ! dest ) ! 74: dest = phdr->p_vaddr; ! 75: if ( ! dest ) { ! 76: DBGC ( image, "ELF %p segment loads to physical address 0\n", ! 77: image ); ! 78: return -ENOEXEC; ! 79: } ! 80: buffer = phys_to_user ( dest ); ! 81: ! 82: DBGC ( image, "ELF %p loading segment [%x,%x) to [%x,%x,%x)\n", image, ! 83: phdr->p_offset, ( phdr->p_offset + phdr->p_filesz ), ! 84: phdr->p_paddr, ( phdr->p_paddr + phdr->p_filesz ), ! 85: ( phdr->p_paddr + phdr->p_memsz ) ); ! 86: ! 87: /* Verify and prepare segment */ ! 88: if ( ( rc = prep_segment ( buffer, phdr->p_filesz, ! 89: phdr->p_memsz ) ) != 0 ) { ! 90: DBGC ( image, "ELF %p could not prepare segment: %s\n", ! 91: image, strerror ( rc ) ); ! 92: return rc; ! 93: } ! 94: ! 95: /* Copy image to segment */ ! 96: memcpy_user ( buffer, 0, image->data, phdr->p_offset, phdr->p_filesz ); ! 97: ! 98: /* Set execution address, if it lies within this segment */ ! 99: if ( ( e_offset = ( ehdr->e_entry - dest ) ) < phdr->p_filesz ) { ! 100: *entry = ehdr->e_entry; ! 101: DBGC ( image, "ELF %p found physical entry point at %lx\n", ! 102: image, *entry ); ! 103: } else if ( ( e_offset = ( ehdr->e_entry - phdr->p_vaddr ) ) ! 104: < phdr->p_filesz ) { ! 105: if ( ! *entry ) { ! 106: *entry = ( dest + e_offset ); ! 107: DBGC ( image, "ELF %p found virtual entry point at %lx" ! 108: " (virt %lx)\n", image, *entry, ! 109: ( ( unsigned long ) ehdr->e_entry ) ); ! 110: } ! 111: } ! 112: ! 113: return 0; ! 114: } ! 115: ! 116: /** ! 117: * Load ELF image into memory ! 118: * ! 119: * @v image ELF file ! 120: * @ret entry Entry point ! 121: * @ret rc Return status code ! 122: */ ! 123: int elf_load ( struct image *image, physaddr_t *entry ) { ! 124: Elf_Ehdr ehdr; ! 125: Elf_Phdr phdr; ! 126: Elf_Off phoff; ! 127: unsigned int phnum; ! 128: int rc; ! 129: ! 130: /* Read ELF header */ ! 131: copy_from_user ( &ehdr, image->data, 0, sizeof ( ehdr ) ); ! 132: if ( memcmp ( &ehdr.e_ident[EI_MAG0], ELFMAG, SELFMAG ) != 0 ) { ! 133: DBGC ( image, "ELF %p has invalid signature\n", image ); ! 134: return -ENOEXEC; ! 135: } ! 136: ! 137: /* Invalidate entry point */ ! 138: *entry = 0; ! 139: ! 140: /* Read ELF program headers */ ! 141: for ( phoff = ehdr.e_phoff , phnum = ehdr.e_phnum ; phnum ; ! 142: phoff += ehdr.e_phentsize, phnum-- ) { ! 143: if ( phoff > image->len ) { ! 144: DBGC ( image, "ELF %p program header %d outside " ! 145: "image\n", image, phnum ); ! 146: return -ENOEXEC; ! 147: } ! 148: copy_from_user ( &phdr, image->data, phoff, sizeof ( phdr ) ); ! 149: if ( ( rc = elf_load_segment ( image, &phdr, &ehdr, ! 150: entry ) ) != 0 ) { ! 151: return rc; ! 152: } ! 153: } ! 154: ! 155: /* Check for a valid execution address */ ! 156: if ( ! *entry ) { ! 157: DBGC ( image, "ELF %p entry point %lx outside image\n", ! 158: image, ( ( unsigned long ) ehdr.e_entry ) ); ! 159: return -ENOEXEC; ! 160: } ! 161: ! 162: return 0; ! 163: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.