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 
error(const char * msg)56 static inline void error(const char *msg)
57 {
58     fputs(msg, stderr);
59 }
60 
boot_raw(void * ptr,size_t len,addr_t where,char ** argv)61 int 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     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(&regs, 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, &regs);
184 
185 bail:
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 
main(int argc,char * argv[])195 int 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