|
|
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.