source: bootcd/isolinux/syslinux-6.03/com32/modules/elf.c @ 26ffad7

Last change on this file since 26ffad7 was e16e8f2, checked in by Edwin Eefting <edwin@datux.nl>, 3 years ago

bootstuff

  • Property mode set to 100644
File size: 8.0 KB
Line 
1/* ----------------------------------------------------------------------- *
2 *
3 *   Copyright 2007-2008 H. Peter Anvin - All Rights Reserved
4 *
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:
13 *
14 *   The above copyright notice and this permission notice shall
15 *   be included in all copies or substantial portions of the Software.
16 *
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.
25 *
26 * ----------------------------------------------------------------------- */
27
28/*
29 * elf.c
30 *
31 * Module to load a protected-mode ELF kernel
32 */
33
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>
46
47#include <syslinux/loadfile.h>
48#include <syslinux/movebits.h>
49#include <syslinux/bootpm.h>
50
51/* If we don't have this much memory for the stack, signal failure */
52#define MIN_STACK       512
53
54static inline void error(const char *msg)
55{
56    fputs(msg, stderr);
57}
58
59int boot_elf(void *ptr, size_t len, char **argv)
60{
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;
78
79    memset(&regs, 0, sizeof regs);
80
81    /*
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.
86     */
87
88    if (len < sizeof(Elf32_Ehdr))
89        goto bail;
90
91    /* Must be ELF, 32-bit, littleendian, version 1 */
92    if (memcmp(eh->e_ident, "\x7f" "ELF\1\1\1", 6))
93        goto bail;
94
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;
102
103    if (eh->e_version != EV_CURRENT)
104        goto bail;
105
106    if (eh->e_ehsize < sizeof(Elf32_Ehdr) || eh->e_ehsize >= len)
107        goto bail;
108
109    if (eh->e_phentsize < sizeof(Elf32_Phdr))
110        goto bail;
111
112    if (!eh->e_phnum)
113        goto bail;
114
115    if (eh->e_phoff + eh->e_phentsize * eh->e_phnum > len)
116        goto bail;
117
118    mmap = syslinux_memory_map();
119    amap = syslinux_dup_memmap(mmap);
120    if (!mmap || !amap)
121        goto bail;
122
123    dprintf("Initial memory map:\n");
124    syslinux_dump_memmap(mmap);
125
126    ph = (Elf32_Phdr *) (cptr + eh->e_phoff);
127
128    for (i = 0; i < eh->e_phnum; i++) {
129        if (ph->p_type == PT_LOAD || ph->p_type == PT_PHDR) {
130            /* This loads at p_paddr, which is arguably the correct semantics.
131               The SysV spec says that SysV loads at p_vaddr (and thus Linux does,
132               too); that is, however, a major brainfuckage in the spec. */
133            addr_t addr = ph->p_paddr;
134            addr_t msize = ph->p_memsz;
135            addr_t dsize = min(msize, ph->p_filesz);
136
137            dprintf("Segment at 0x%08x data 0x%08x len 0x%08x\n",
138                    addr, dsize, msize);
139
140            if (syslinux_memmap_type(amap, addr, msize) != SMT_FREE) {
141                printf("Memory segment at 0x%08x (len 0x%08x) is unavailable\n",
142                       addr, msize);
143                goto bail;      /* Memory region unavailable */
144            }
145
146            /* Mark this region as allocated in the available map */
147            if (syslinux_add_memmap(&amap, addr, dsize, SMT_ALLOC))
148                goto bail;
149
150            if (ph->p_filesz) {
151                /* Data present region.  Create a move entry for it. */
152                if (syslinux_add_movelist
153                    (&ml, addr, (addr_t) cptr + ph->p_offset, dsize))
154                    goto bail;
155            }
156            if (msize > dsize) {
157                /* Zero-filled region.  Mark as a zero region in the memory map. */
158                if (syslinux_add_memmap
159                    (&mmap, addr + dsize, msize - dsize, SMT_ZERO))
160                    goto bail;
161            }
162        } else {
163            /* Ignore this program header */
164        }
165
166        ph = (Elf32_Phdr *) ((char *)ph + eh->e_phentsize);
167    }
168
169    /* Create the invocation record (initial stack frame) */
170
171    argsize = argc = 0;
172    for (argp = argv; *argp; argp++) {
173        dprintf("argv[%2d] = \"%s\"\n", argc, *argp);
174        argc++;
175        argsize += strlen(*argp) + 1;
176    }
177
178    /* We need the argument strings, argument pointers,
179       argc, plus four zero-word terminators. */
180    stack_frame_size = argsize + argc * sizeof(char *) + 5 * sizeof(long);
181    stack_frame_size = (stack_frame_size + 15) & ~15;
182    stack_frame = calloc(stack_frame_size, 1);
183    if (!stack_frame)
184        goto bail;
185
186    dprintf("Right before syslinux_memmap_largest()...\n");
187    syslinux_dump_memmap(amap);
188
189    if (syslinux_memmap_largest(amap, SMT_FREE, &lstart, &llen))
190        goto bail;              /* NO free memory?! */
191
192    if (llen < stack_frame_size + MIN_STACK + 16)
193        goto bail;              /* Insufficient memory  */
194
195    /* Initial stack pointer address */
196    stack_pointer = (lstart + llen - stack_frame_size) & ~15;
197
198    dprintf("Stack frame at 0x%08x len 0x%08x\n",
199            stack_pointer, stack_frame_size);
200
201    /* Create the stack frame.  sfp is the pointer in current memory for
202       the next argument string, sfa is the address in its final resting place.
203       spp is the pointer into the argument array in current memory. */
204    spp = (uint32_t *) stack_frame;
205    sfp = stack_frame + argc * sizeof(char *) + 5 * sizeof(long);
206    sfa = stack_pointer + argc * sizeof(char *) + 5 * sizeof(long);
207
208    *spp++ = argc;
209    for (argp = argv; *argp; argp++) {
210        int bytes = strlen(*argp) + 1;  /* Including final null */
211        *spp++ = sfa;
212        memcpy(sfp, *argp, bytes);
213        sfp += bytes;
214        sfa += bytes;
215    }
216    /* Zero fields are aready taken care of by calloc() */
217
218    /* ... and we'll want to move it into the right place... */
219#if DEBUG
220    if (syslinux_memmap_type(amap, stack_pointer, stack_frame_size)
221        != SMT_FREE) {
222        dprintf("Stack frame area not free (how did that happen?)!\n");
223        goto bail;              /* Memory region unavailable */
224    }
225#endif
226
227    if (syslinux_add_memmap(&amap, stack_pointer, stack_frame_size, SMT_ALLOC))
228        goto bail;
229
230    if (syslinux_add_movelist(&ml, stack_pointer, (addr_t) stack_frame,
231                              stack_frame_size))
232        goto bail;
233
234    memset(&regs, 0, sizeof regs);
235    regs.eip = eh->e_entry;
236    regs.esp = stack_pointer;
237
238    dprintf("Final memory map:\n");
239    syslinux_dump_memmap(mmap);
240
241    dprintf("Final available map:\n");
242    syslinux_dump_memmap(amap);
243
244    dprintf("Movelist:\n");
245    syslinux_dump_movelist(ml);
246
247    /* This should not return... */
248    fputs("Booting...\n", stdout);
249    syslinux_shuffle_boot_pm(ml, mmap, 0, &regs);
250
251bail:
252    if (stack_frame)
253        free(stack_frame);
254    syslinux_free_memmap(amap);
255    syslinux_free_memmap(mmap);
256    syslinux_free_movelist(ml);
257
258    return -1;
259}
260
261int main(int argc, char *argv[])
262{
263    void *data;
264    size_t data_len;
265
266    if (argc < 2) {
267        error("Usage: elf.c32 elf_file arguments...\n");
268        return 1;
269    }
270
271    if (zloadfile(argv[1], &data, &data_len)) {
272        error("Unable to load file\n");
273        return 1;
274    }
275
276    boot_elf(data, data_len, &argv[1]);
277    error("Invalid ELF file or insufficient memory\n");
278    return 1;
279}
Note: See TracBrowser for help on using the repository browser.