3064a94f51827ee56b4f707f87bccbe3e20924a0
[profile/ivi/syslinux.git] / com32 / modules / pmload.c
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
56 static inline void error(const char *msg)
57 {
58     fputs(msg, stderr);
59 }
60
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 #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
191 bail:
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
201 int 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 }