syslinux/com32/modules/pmload.c
<<
>>
Prefs
   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 * pmload.c
  30 *
  31 * Load a binary file and run it in protected mode.  We give it
  32 * an ELF-style invocation record, becase, why not?
  33 *
  34 * Usage: pmload.c32 filename address [arguments...]
  35 */
  36
  37#include <stdio.h>
  38#include <stdlib.h>
  39#include <inttypes.h>
  40#include <string.h>
  41#include <fcntl.h>
  42#include <unistd.h>
  43#include <errno.h>
  44#include <sys/stat.h>
  45#include <elf.h>
  46#include <console.h>
  47#include <dprintf.h>
  48
  49#include <syslinux/loadfile.h>
  50#include <syslinux/movebits.h>
  51#include <syslinux/bootpm.h>
  52
  53/* If we don't have this much memory for the stack, signal failure */
  54#define MIN_STACK       512
  55
  56static inline void error(const char *msg)
  57{
  58    fputs(msg, stderr);
  59}
  60
  61int boot_raw(void *ptr, size_t len, addr_t where, char **argv)
  62{
  63    struct syslinux_movelist *ml = NULL;
  64    struct syslinux_memmap *mmap = NULL, *amap = NULL;
  65    struct syslinux_pm_regs regs;
  66    int argc;
  67    addr_t argsize;
  68    char **argp;
  69    addr_t lstart, llen;
  70    char *stack_frame = NULL;
  71    addr_t stack_frame_size;
  72    addr_t stack_pointer;
  73    uint32_t *spp;
  74    char *sfp;
  75    addr_t sfa;
  76
  77    memset(&regs, 0, sizeof regs);
  78
  79    mmap = syslinux_memory_map();
  80    amap = syslinux_dup_memmap(mmap);
  81    if (!mmap || !amap)
  82        goto bail;
  83
  84#if DEBUG
  85    dprintf("Initial memory map:\n");
  86    syslinux_dump_memmap(stdout, mmap);
  87#endif
  88
  89    dprintf("Segment at 0x%08x len 0x%08x\n", where, len);
  90
  91    if (syslinux_memmap_type(amap, where, len) != SMT_FREE) {
  92        printf("Memory segment at 0x%08x (len 0x%08x) is unavailable\n",
  93               where, len);
  94        goto bail;              /* Memory region unavailable */
  95    }
  96
  97    /* Mark this region as allocated in the available map */
  98    if (syslinux_add_memmap(&amap, where, len, SMT_ALLOC))
  99        goto bail;
 100
 101    /* Data present region.  Create a move entry for it. */
 102    if (syslinux_add_movelist(&ml, where, (addr_t) ptr, len))
 103        goto bail;
 104
 105    /* Create the invocation record (initial stack frame) */
 106
 107    argsize = argc = 0;
 108    for (argp = argv; *argp; argp++) {
 109        dprintf("argv[%2d] = \"%s\"\n", argc, *argp);
 110        argc++;
 111        argsize += strlen(*argp) + 1;
 112    }
 113
 114    /* We need the argument strings, argument pointers,
 115       argc, plus four zero-word terminators. */
 116    stack_frame_size = argsize + argc * sizeof(char *) + 5 * sizeof(long);
 117    stack_frame_size = (stack_frame_size + 15) & ~15;
 118    stack_frame = calloc(stack_frame_size, 1);
 119    if (!stack_frame)
 120        goto bail;
 121
 122#if DEBUG
 123    dprintf("Right before syslinux_memmap_largest()...\n");
 124    syslinux_dump_memmap(stdout, amap);
 125#endif
 126
 127    if (syslinux_memmap_largest(amap, SMT_FREE, &lstart, &llen))
 128        goto bail;              /* NO free memory?! */
 129
 130    if (llen < stack_frame_size + MIN_STACK + 16)
 131        goto bail;              /* Insufficient memory  */
 132
 133    /* Initial stack pointer address */
 134    stack_pointer = (lstart + llen - stack_frame_size) & ~15;
 135
 136    dprintf("Stack frame at 0x%08x len 0x%08x\n",
 137            stack_pointer, stack_frame_size);
 138
 139    /* Create the stack frame.  sfp is the pointer in current memory for
 140       the next argument string, sfa is the address in its final resting place.
 141       spp is the pointer into the argument array in current memory. */
 142    spp = (uint32_t *) stack_frame;
 143    sfp = stack_frame + argc * sizeof(char *) + 5 * sizeof(long);
 144    sfa = stack_pointer + argc * sizeof(char *) + 5 * sizeof(long);
 145
 146    *spp++ = argc;
 147    for (argp = argv; *argp; argp++) {
 148        int bytes = strlen(*argp) + 1;  /* Including final null */
 149        *spp++ = sfa;
 150        memcpy(sfp, *argp, bytes);
 151        sfp += bytes;
 152        sfa += bytes;
 153    }
 154    /* Zero fields are aready taken care of by calloc() */
 155
 156    /* ... and we'll want to move it into the right place... */
 157#if DEBUG
 158    if (syslinux_memmap_type(amap, stack_pointer, stack_frame_size)
 159        != SMT_FREE) {
 160        dprintf("Stack frame area not free (how did that happen?)!\n");
 161        goto bail;              /* Memory region unavailable */
 162    }
 163#endif
 164
 165    if (syslinux_add_memmap(&amap, stack_pointer, stack_frame_size, SMT_ALLOC))
 166        goto bail;
 167
 168    if (syslinux_add_movelist(&ml, stack_pointer, (addr_t) stack_frame,
 169                              stack_frame_size))
 170        goto bail;
 171
 172    memset(&regs, 0, sizeof regs);
 173    regs.eip = where;
 174    regs.esp = stack_pointer;
 175
 176#if DEBUG
 177    dprintf("Final memory map:\n");
 178    syslinux_dump_memmap(stdout, mmap);
 179
 180    dprintf("Final available map:\n");
 181    syslinux_dump_memmap(stdout, amap);
 182
 183    dprintf("Movelist:\n");
 184    syslinux_dump_movelist(stdout, ml);
 185#endif
 186
 187    /* This should not return... */
 188    fputs("Booting...\n", stdout);
 189    syslinux_shuffle_boot_pm(ml, mmap, 0, &regs);
 190
 191bail:
 192    if (stack_frame)
 193        free(stack_frame);
 194    syslinux_free_memmap(amap);
 195    syslinux_free_memmap(mmap);
 196    syslinux_free_movelist(ml);
 197
 198    return -1;
 199}
 200
 201int main(int argc, char *argv[])
 202{
 203    void *data;
 204    size_t data_len;
 205    addr_t where;
 206
 207    openconsole(&dev_null_r, &dev_stdcon_w);
 208
 209    if (argc < 3) {
 210        error("Usage: pmload.c32 bin_file address arguments...\n");
 211        return 1;
 212    }
 213
 214    where = strtoul(argv[2], NULL, 0);
 215
 216    if (loadfile(argv[1], &data, &data_len)) {
 217        error("Unable to load file\n");
 218        return 1;
 219    }
 220
 221    boot_raw(data, data_len, where, &argv[1]);
 222    error("Failed to boot, probably insufficient memory\n");
 223    return 1;
 224}
 225
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.