Merging upstream version 3.60~pre6.
[syslinux-debian/hramrach.git] / com32 / modules / elf.c
blob35463c28185d72cf7106e138dde260625076ccb0
1 /* ----------------------------------------------------------------------- *
3 * Copyright 2007 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 <sys/stat.h>
42 #include <elf.h>
43 #include <console.h>
45 #include <syslinux/loadfile.h>
46 #include <syslinux/movebits.h>
47 #include <syslinux/bootpm.h>
49 /* If we don't have this much memory for the stack, signal failure */
50 #define MIN_STACK 512
52 #define DEBUG 0
53 #if DEBUG
54 # define dprintf printf
55 #else
56 # define dprintf(f, ...) ((void)0)
57 #endif
59 static inline void error(const char *msg)
61 fputs(msg, stderr);
64 int boot_elf(void *ptr, size_t len, char **argv)
66 char *cptr = ptr;
67 Elf32_Ehdr *eh = ptr;
68 Elf32_Phdr *ph;
69 unsigned int i;
70 struct syslinux_movelist *ml = NULL;
71 struct syslinux_memmap *mmap = NULL, *amap = NULL;
72 struct syslinux_pm_regs regs;
73 int argc;
74 addr_t argsize;
75 char **argp;
76 addr_t lstart, llen;
77 char *stack_frame = NULL;
78 addr_t stack_frame_size;
79 addr_t stack_pointer;
80 uint32_t *spp;
81 char *sfp;
82 addr_t sfa;
84 memset(&regs, 0, sizeof regs);
87 * Note: mmap is the memory map (containing free and zeroed regions)
88 * needed by syslinux_shuffle_boot_pm(); amap is a map where we keep
89 * track ourselves which target memory ranges have already been
90 * allocated.
93 if ( len < sizeof(Elf32_Ehdr) )
94 goto bail;
96 /* Must be ELF, 32-bit, littleendian, version 1 */
97 if ( memcmp(eh->e_ident, "\x7f""ELF\1\1\1", 6) )
98 goto bail;
100 /* Is this a worthwhile test? In particular x86-64 normally
101 would imply ELF64 support, which we could do as long as
102 the addresses are 32-bit addresses, and entry is 32 bits.
103 64-bit addresses would take a lot more work. */
104 if ( eh->e_machine != EM_386 && eh->e_machine != EM_486 &&
105 eh->e_machine != EM_X86_64 )
106 goto bail;
108 if ( eh->e_version != EV_CURRENT )
109 goto bail;
111 if ( eh->e_ehsize < sizeof(Elf32_Ehdr) || eh->e_ehsize >= len )
112 goto bail;
114 if ( eh->e_phentsize < sizeof(Elf32_Phdr) )
115 goto bail;
117 if ( !eh->e_phnum )
118 goto bail;
120 if ( eh->e_phoff+eh->e_phentsize*eh->e_phnum > len )
121 goto bail;
123 mmap = syslinux_memory_map();
124 amap = syslinux_dup_memmap(mmap);
125 if (!mmap || !amap)
126 goto bail;
128 #if DEBUG
129 dprintf("Initial memory map:\n");
130 syslinux_dump_memmap(stdout, mmap);
131 #endif
133 ph = (Elf32_Phdr *)(cptr+eh->e_phoff);
135 for (i = 0; i < eh->e_phnum; i++) {
136 if (ph->p_type == PT_LOAD && ph->p_memsz >= ph->p_filesz) {
137 /* This loads at p_paddr, which is arguably the correct semantics.
138 The SysV spec says that SysV loads at p_vaddr (and thus Linux does,
139 too); that is, however, a major brainfuckage in the spec. */
141 dprintf("Segment at 0x%08x len 0x%08x\n", ph->p_paddr, ph->p_memsz);
143 if (syslinux_memmap_type(amap, ph->p_paddr, ph->p_memsz) != SMT_FREE) {
144 printf("Memory segment at 0x%08x (len 0x%08x) is unavailable\n",
145 ph->p_paddr, ph->p_memsz);
146 goto bail; /* Memory region unavailable */
149 /* Mark this region as allocated in the available map */
150 if (syslinux_add_memmap(&amap, ph->p_paddr, ph->p_memsz, SMT_ALLOC))
151 goto bail;
153 if (ph->p_filesz) {
154 /* Data present region. Create a move entry for it. */
155 if (syslinux_add_movelist(&ml, ph->p_paddr, (addr_t)cptr+ph->p_offset,
156 ph->p_filesz))
157 goto bail;
159 if (ph->p_memsz > ph->p_filesz) {
160 /* Zero-filled region. Mark as a zero region in the memory map. */
161 if (syslinux_add_memmap(&mmap, ph->p_paddr+ph->p_filesz,
162 ph->p_memsz - ph->p_filesz, SMT_ZERO))
163 goto bail;
165 } else {
166 /* Ignore this program header */
169 ph = (Elf32_Phdr *)((char *)ph + eh->e_phentsize);
172 /* Create the invocation record (initial stack frame) */
174 argsize = argc = 0;
175 for (argp = argv; *argp; argp++) {
176 dprintf("argv[%2d] = \"%s\"\n", argc, *argp);
177 argc++;
178 argsize += strlen(*argp)+1;
181 /* We need the argument strings, argument pointers,
182 argc, plus four zero-word terminators. */
183 stack_frame_size = argsize + argc*sizeof(char *) + 5*sizeof(long);
184 stack_frame_size = (stack_frame_size+15) & ~15;
185 stack_frame = calloc(stack_frame_size, 1);
186 if (!stack_frame)
187 goto bail;
189 #if DEBUG
190 dprintf("Right before syslinux_memmap_largest()...\n");
191 syslinux_dump_memmap(stdout, amap);
192 #endif
194 if (syslinux_memmap_largest(amap, SMT_FREE, &lstart, &llen))
195 goto bail; /* NO free memory?! */
197 if (llen < stack_frame_size+MIN_STACK+16)
198 goto bail; /* Insufficient memory */
200 /* Initial stack pointer address */
201 stack_pointer = (lstart+llen-stack_frame_size) & ~15;
203 dprintf("Stack frame at 0x%08x len 0x%08x\n",
204 stack_pointer, stack_frame_size);
206 /* Create the stack frame. sfp is the pointer in current memory for
207 the next argument string, sfa is the address in its final resting place.
208 spp is the pointer into the argument array in current memory. */
209 spp = (uint32_t *)stack_frame;
210 sfp = stack_frame + argc*sizeof(char *) + 5*sizeof(long);
211 sfa = stack_pointer + argc*sizeof(char *) + 5*sizeof(long);
213 *spp++ = argc;
214 for (argp = argv; *argp; argp++) {
215 int bytes = strlen(*argp) + 1; /* Including final null */
216 *spp++ = sfa;
217 memcpy(sfp, *argp, bytes);
218 sfp += bytes;
219 sfa += bytes;
221 /* Zero fields are aready taken care of by calloc() */
223 /* ... and we'll want to move it into the right place... */
224 #if DEBUG
225 if (syslinux_memmap_type(amap, stack_pointer, stack_frame_size)
226 != SMT_FREE) {
227 dprintf("Stack frame area not free (how did that happen?)!\n");
228 goto bail; /* Memory region unavailable */
230 #endif
232 if (syslinux_add_memmap(&amap, stack_pointer, stack_frame_size, SMT_ALLOC))
233 goto bail;
235 if (syslinux_add_movelist(&ml, stack_pointer, (addr_t)stack_frame,
236 stack_frame_size))
237 goto bail;
239 memset(&regs, 0, sizeof regs);
240 regs.eip = eh->e_entry;
241 regs.esp = stack_pointer;
243 #if DEBUG
244 dprintf("Final memory map:\n");
245 syslinux_dump_memmap(stdout, mmap);
247 dprintf("Final available map:\n");
248 syslinux_dump_memmap(stdout, amap);
250 dprintf("Movelist:\n");
251 syslinux_dump_movelist(stdout, ml);
252 #endif
254 /* This should not return... */
255 fputs("Booting...\n", stdout);
256 syslinux_shuffle_boot_pm(ml, mmap, 0, &regs);
258 bail:
259 if (stack_frame)
260 free(stack_frame);
261 syslinux_free_memmap(amap);
262 syslinux_free_memmap(mmap);
263 syslinux_free_movelist(ml);
265 return -1;
268 int main(int argc, char *argv[])
270 void *data;
271 size_t data_len;
273 openconsole(&dev_null_r, &dev_stdcon_w);
275 if (argc < 2) {
276 error("Usage: elf.c32 elf_file arguments...\n");
277 return 1;
280 if (loadfile(argv[1], &data, &data_len)) {
281 error("Unable to load file\n");
282 return 1;
285 boot_elf(data, data_len, &argv[1]);
286 error("Invalid ELF file or insufficient memory\n");
287 return 1;