Adding upstream version 4.02+dfsg.
[syslinux-debian/hramrach.git] / com32 / modules / elf.c
blob182afa605c57eab0c2c1753e291d5c622faa4960
1 /* ----------------------------------------------------------------------- *
3 * Copyright 2007-2008 H. Peter Anvin - All Rights Reserved
5 * Permission is hereby granted, free of charge, to any person
6 * obtaining a copy of this software and associated documentation
7 * files (the "Software"), to deal in the Software without
8 * restriction, including without limitation the rights to use,
9 * copy, modify, merge, publish, distribute, sublicense, and/or
10 * sell copies of the Software, and to permit persons to whom
11 * the Software is furnished to do so, subject to the following
12 * conditions:
14 * The above copyright notice and this permission notice shall
15 * be included in all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
19 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24 * OTHER DEALINGS IN THE SOFTWARE.
26 * ----------------------------------------------------------------------- */
29 * elf.c
31 * Module to load a protected-mode ELF kernel
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <inttypes.h>
37 #include <string.h>
38 #include <fcntl.h>
39 #include <unistd.h>
40 #include <errno.h>
41 #include <minmax.h>
42 #include <sys/stat.h>
43 #include <elf.h>
44 #include <console.h>
45 #include <dprintf.h>
47 #include <syslinux/loadfile.h>
48 #include <syslinux/movebits.h>
49 #include <syslinux/bootpm.h>
51 /* If we don't have this much memory for the stack, signal failure */
52 #define MIN_STACK 512
54 static inline void error(const char *msg)
56 fputs(msg, stderr);
59 int boot_elf(void *ptr, size_t len, char **argv)
61 char *cptr = ptr;
62 Elf32_Ehdr *eh = ptr;
63 Elf32_Phdr *ph;
64 unsigned int i;
65 struct syslinux_movelist *ml = NULL;
66 struct syslinux_memmap *mmap = NULL, *amap = NULL;
67 struct syslinux_pm_regs regs;
68 int argc;
69 addr_t argsize;
70 char **argp;
71 addr_t lstart, llen;
72 char *stack_frame = NULL;
73 addr_t stack_frame_size;
74 addr_t stack_pointer;
75 uint32_t *spp;
76 char *sfp;
77 addr_t sfa;
79 memset(&regs, 0, sizeof regs);
82 * Note: mmap is the memory map (containing free and zeroed regions)
83 * needed by syslinux_shuffle_boot_pm(); amap is a map where we keep
84 * track ourselves which target memory ranges have already been
85 * allocated.
88 if (len < sizeof(Elf32_Ehdr))
89 goto bail;
91 /* Must be ELF, 32-bit, littleendian, version 1 */
92 if (memcmp(eh->e_ident, "\x7f" "ELF\1\1\1", 6))
93 goto bail;
95 /* Is this a worthwhile test? In particular x86-64 normally
96 would imply ELF64 support, which we could do as long as
97 the addresses are 32-bit addresses, and entry is 32 bits.
98 64-bit addresses would take a lot more work. */
99 if (eh->e_machine != EM_386 && eh->e_machine != EM_486 &&
100 eh->e_machine != EM_X86_64)
101 goto bail;
103 if (eh->e_version != EV_CURRENT)
104 goto bail;
106 if (eh->e_ehsize < sizeof(Elf32_Ehdr) || eh->e_ehsize >= len)
107 goto bail;
109 if (eh->e_phentsize < sizeof(Elf32_Phdr))
110 goto bail;
112 if (!eh->e_phnum)
113 goto bail;
115 if (eh->e_phoff + eh->e_phentsize * eh->e_phnum > len)
116 goto bail;
118 mmap = syslinux_memory_map();
119 amap = syslinux_dup_memmap(mmap);
120 if (!mmap || !amap)
121 goto bail;
123 #if DEBUG
124 dprintf("Initial memory map:\n");
125 syslinux_dump_memmap(stdout, mmap);
126 #endif
128 ph = (Elf32_Phdr *) (cptr + eh->e_phoff);
130 for (i = 0; i < eh->e_phnum; i++) {
131 if (ph->p_type == PT_LOAD || ph->p_type == PT_PHDR) {
132 /* This loads at p_paddr, which is arguably the correct semantics.
133 The SysV spec says that SysV loads at p_vaddr (and thus Linux does,
134 too); that is, however, a major brainfuckage in the spec. */
135 addr_t addr = ph->p_paddr;
136 addr_t msize = ph->p_memsz;
137 addr_t dsize = min(msize, ph->p_filesz);
139 dprintf("Segment at 0x%08x data 0x%08x len 0x%08x\n",
140 addr, dsize, msize);
142 if (syslinux_memmap_type(amap, addr, msize) != SMT_FREE) {
143 printf("Memory segment at 0x%08x (len 0x%08x) is unavailable\n",
144 addr, msize);
145 goto bail; /* Memory region unavailable */
148 /* Mark this region as allocated in the available map */
149 if (syslinux_add_memmap(&amap, addr, dsize, SMT_ALLOC))
150 goto bail;
152 if (ph->p_filesz) {
153 /* Data present region. Create a move entry for it. */
154 if (syslinux_add_movelist
155 (&ml, addr, (addr_t) cptr + ph->p_offset, dsize))
156 goto bail;
158 if (msize > dsize) {
159 /* Zero-filled region. Mark as a zero region in the memory map. */
160 if (syslinux_add_memmap
161 (&mmap, addr + dsize, msize - dsize, SMT_ZERO))
162 goto bail;
164 } else {
165 /* Ignore this program header */
168 ph = (Elf32_Phdr *) ((char *)ph + eh->e_phentsize);
171 /* Create the invocation record (initial stack frame) */
173 argsize = argc = 0;
174 for (argp = argv; *argp; argp++) {
175 dprintf("argv[%2d] = \"%s\"\n", argc, *argp);
176 argc++;
177 argsize += strlen(*argp) + 1;
180 /* We need the argument strings, argument pointers,
181 argc, plus four zero-word terminators. */
182 stack_frame_size = argsize + argc * sizeof(char *) + 5 * sizeof(long);
183 stack_frame_size = (stack_frame_size + 15) & ~15;
184 stack_frame = calloc(stack_frame_size, 1);
185 if (!stack_frame)
186 goto bail;
188 #if DEBUG
189 dprintf("Right before syslinux_memmap_largest()...\n");
190 syslinux_dump_memmap(stdout, amap);
191 #endif
193 if (syslinux_memmap_largest(amap, SMT_FREE, &lstart, &llen))
194 goto bail; /* NO free memory?! */
196 if (llen < stack_frame_size + MIN_STACK + 16)
197 goto bail; /* Insufficient memory */
199 /* Initial stack pointer address */
200 stack_pointer = (lstart + llen - stack_frame_size) & ~15;
202 dprintf("Stack frame at 0x%08x len 0x%08x\n",
203 stack_pointer, stack_frame_size);
205 /* Create the stack frame. sfp is the pointer in current memory for
206 the next argument string, sfa is the address in its final resting place.
207 spp is the pointer into the argument array in current memory. */
208 spp = (uint32_t *) stack_frame;
209 sfp = stack_frame + argc * sizeof(char *) + 5 * sizeof(long);
210 sfa = stack_pointer + argc * sizeof(char *) + 5 * sizeof(long);
212 *spp++ = argc;
213 for (argp = argv; *argp; argp++) {
214 int bytes = strlen(*argp) + 1; /* Including final null */
215 *spp++ = sfa;
216 memcpy(sfp, *argp, bytes);
217 sfp += bytes;
218 sfa += bytes;
220 /* Zero fields are aready taken care of by calloc() */
222 /* ... and we'll want to move it into the right place... */
223 #if DEBUG
224 if (syslinux_memmap_type(amap, stack_pointer, stack_frame_size)
225 != SMT_FREE) {
226 dprintf("Stack frame area not free (how did that happen?)!\n");
227 goto bail; /* Memory region unavailable */
229 #endif
231 if (syslinux_add_memmap(&amap, stack_pointer, stack_frame_size, SMT_ALLOC))
232 goto bail;
234 if (syslinux_add_movelist(&ml, stack_pointer, (addr_t) stack_frame,
235 stack_frame_size))
236 goto bail;
238 memset(&regs, 0, sizeof regs);
239 regs.eip = eh->e_entry;
240 regs.esp = stack_pointer;
242 #if DEBUG
243 dprintf("Final memory map:\n");
244 syslinux_dump_memmap(stdout, mmap);
246 dprintf("Final available map:\n");
247 syslinux_dump_memmap(stdout, amap);
249 dprintf("Movelist:\n");
250 syslinux_dump_movelist(stdout, ml);
251 #endif
253 /* This should not return... */
254 fputs("Booting...\n", stdout);
255 syslinux_shuffle_boot_pm(ml, mmap, 0, &regs);
257 bail:
258 if (stack_frame)
259 free(stack_frame);
260 syslinux_free_memmap(amap);
261 syslinux_free_memmap(mmap);
262 syslinux_free_movelist(ml);
264 return -1;
267 int main(int argc, char *argv[])
269 void *data;
270 size_t data_len;
272 openconsole(&dev_null_r, &dev_stdcon_w);
274 if (argc < 2) {
275 error("Usage: elf.c32 elf_file arguments...\n");
276 return 1;
279 if (zloadfile(argv[1], &data, &data_len)) {
280 error("Unable to load file\n");
281 return 1;
284 boot_elf(data, data_len, &argv[1]);
285 error("Invalid ELF file or insufficient memory\n");
286 return 1;