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(®s, 0, sizeof regs); 78 79 mmap = syslinux_memory_map(); 80 amap = syslinux_dup_memmap(mmap); 81 if (!mmap || !amap) 82 goto bail; 83 84 dprintf("Initial memory map:\n"); 85 syslinux_dump_memmap(mmap); 86 87 dprintf("Segment at 0x%08x len 0x%08x\n", where, len); 88 89 if (syslinux_memmap_type(amap, where, len) != SMT_FREE) { 90 printf("Memory segment at 0x%08x (len 0x%08x) is unavailable\n", 91 where, len); 92 goto bail; /* Memory region unavailable */ 93 } 94 95 /* Mark this region as allocated in the available map */ 96 if (syslinux_add_memmap(&amap, where, len, SMT_ALLOC)) 97 goto bail; 98 99 /* Data present region. Create a move entry for it. */ 100 if (syslinux_add_movelist(&ml, where, (addr_t) ptr, len)) 101 goto bail; 102 103 /* Create the invocation record (initial stack frame) */ 104 105 argsize = argc = 0; 106 for (argp = argv; *argp; argp++) { 107 dprintf("argv[%2d] = \"%s\"\n", argc, *argp); 108 argc++; 109 argsize += strlen(*argp) + 1; 110 } 111 112 /* We need the argument strings, argument pointers, 113 argc, plus four zero-word terminators. */ 114 stack_frame_size = argsize + argc * sizeof(char *) + 5 * sizeof(long); 115 stack_frame_size = (stack_frame_size + 15) & ~15; 116 stack_frame = calloc(stack_frame_size, 1); 117 if (!stack_frame) 118 goto bail; 119 120 dprintf("Right before syslinux_memmap_largest()...\n"); 121 syslinux_dump_memmap(amap); 122 123 if (syslinux_memmap_largest(amap, SMT_FREE, &lstart, &llen)) 124 goto bail; /* NO free memory?! */ 125 126 if (llen < stack_frame_size + MIN_STACK + 16) 127 goto bail; /* Insufficient memory */ 128 129 /* Initial stack pointer address */ 130 stack_pointer = (lstart + llen - stack_frame_size) & ~15; 131 132 dprintf("Stack frame at 0x%08x len 0x%08x\n", 133 stack_pointer, stack_frame_size); 134 135 /* Create the stack frame. sfp is the pointer in current memory for 136 the next argument string, sfa is the address in its final resting place. 137 spp is the pointer into the argument array in current memory. */ 138 spp = (uint32_t *) stack_frame; 139 sfp = stack_frame + argc * sizeof(char *) + 5 * sizeof(long); 140 sfa = stack_pointer + argc * sizeof(char *) + 5 * sizeof(long); 141 142 *spp++ = argc; 143 for (argp = argv; *argp; argp++) { 144 int bytes = strlen(*argp) + 1; /* Including final null */ 145 *spp++ = sfa; 146 memcpy(sfp, *argp, bytes); 147 sfp += bytes; 148 sfa += bytes; 149 } 150 /* Zero fields are aready taken care of by calloc() */ 151 152 /* ... and we'll want to move it into the right place... */ 153#if DEBUG 154 if (syslinux_memmap_type(amap, stack_pointer, stack_frame_size) 155 != SMT_FREE) { 156 dprintf("Stack frame area not free (how did that happen?)!\n"); 157 goto bail; /* Memory region unavailable */ 158 } 159#endif 160 161 if (syslinux_add_memmap(&amap, stack_pointer, stack_frame_size, SMT_ALLOC)) 162 goto bail; 163 164 if (syslinux_add_movelist(&ml, stack_pointer, (addr_t) stack_frame, 165 stack_frame_size)) 166 goto bail; 167 168 memset(®s, 0, sizeof regs); 169 regs.eip = where; 170 regs.esp = stack_pointer; 171 172 dprintf("Final memory map:\n"); 173 syslinux_dump_memmap(mmap); 174 175 dprintf("Final available map:\n"); 176 syslinux_dump_memmap(amap); 177 178 dprintf("Movelist:\n"); 179 syslinux_dump_movelist(ml); 180 181 /* This should not return... */ 182 fputs("Booting...\n", stdout); 183 syslinux_shuffle_boot_pm(ml, mmap, 0, ®s); 184 185bail: 186 if (stack_frame) 187 free(stack_frame); 188 syslinux_free_memmap(amap); 189 syslinux_free_memmap(mmap); 190 syslinux_free_movelist(ml); 191 192 return -1; 193} 194 195int main(int argc, char *argv[]) 196{ 197 void *data; 198 size_t data_len; 199 addr_t where; 200 201 if (argc < 3) { 202 error("Usage: pmload.c32 bin_file address arguments...\n"); 203 return 1; 204 } 205 206 where = strtoul(argv[2], NULL, 0); 207 208 if (loadfile(argv[1], &data, &data_len)) { 209 error("Unable to load file\n"); 210 return 1; 211 } 212 213 boot_raw(data, data_len, where, &argv[1]); 214 error("Failed to boot, probably insufficient memory\n"); 215 return 1; 216} 217