1 /* ----------------------------------------------------------------------- *
2 *
3 * Copyright 2007-2008 H. Peter Anvin - All Rights Reserved
4 * Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
5 *
6 * Permission is hereby granted, free of charge, to any person
7 * obtaining a copy of this software and associated documentation
8 * files (the "Software"), to deal in the Software without
9 * restriction, including without limitation the rights to use,
10 * copy, modify, merge, publish, distribute, sublicense, and/or
11 * sell copies of the Software, and to permit persons to whom
12 * the Software is furnished to do so, subject to the following
13 * conditions:
14 *
15 * The above copyright notice and this permission notice shall
16 * be included in all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 * OTHER DEALINGS IN THE SOFTWARE.
26 *
27 * ----------------------------------------------------------------------- */
28
29 /*
30 * mboot.c
31 *
32 * Module to load a multiboot kernel
33 */
34
35 #include "mboot.h"
36
37 struct multiboot_info mbinfo;
38 struct syslinux_pm_regs regs;
39 struct my_options opt, set;
40
41 struct module_data {
42 void *data;
43 size_t len;
44 const char *cmdline;
45 };
46
map_modules(struct module_data * modules,int nmodules)47 static int map_modules(struct module_data *modules, int nmodules)
48 {
49 struct mod_list *mod_list;
50 addr_t map_list = 0;
51 size_t list_size = nmodules * sizeof *mod_list;
52 int i;
53
54 mod_list = malloc(list_size);
55 if (!mod_list) {
56 printf("Failed to allocate module list\n");
57 return -1;
58 }
59
60 map_list = map_data(mod_list, list_size, 16, 0);
61 if (!map_list) {
62 printf("Cannot map module list\n");
63 return -1;
64 }
65
66 for (i = 0; i < nmodules; i++) {
67 addr_t mod_map = 0;
68 addr_t cmd_map = 0;
69
70 dprintf("Module %d cmdline: \"%s\"\n", i, modules[i].cmdline);
71
72 cmd_map = map_string(modules[i].cmdline);
73
74 mod_map = map_data(modules[i].data, modules[i].len, 4096, MAP_HIGH);
75 if (!mod_map) {
76 printf("Failed to map module (memory fragmentation issue?)\n");
77 return -1;
78 }
79 mod_list[i].mod_start = mod_map;
80 mod_list[i].mod_end = mod_map + modules[i].len;
81 mod_list[i].cmdline = cmd_map;
82 mod_list[i].pad = 0;
83 }
84
85 mbinfo.flags |= MB_INFO_MODS;
86 mbinfo.mods_count = nmodules;
87 mbinfo.mods_addr = map_list;
88 return 0;
89 }
90
get_modules(char ** argv,struct module_data ** mdp)91 static int get_modules(char **argv, struct module_data **mdp)
92 {
93 char **argp, **argx;
94 struct module_data *mp;
95 int rv;
96 int module_count = 1;
97 int arglen;
98 const char module_separator[] = "---";
99
100 for (argp = argv; *argp; argp++) {
101 if (!strcmp(*argp, module_separator))
102 module_count++;
103 }
104
105 *mdp = mp = malloc(module_count * sizeof(struct module_data));
106 if (!mp) {
107 error("Out of memory!\n");
108 return -1;
109 }
110
111 argp = argv;
112 while (*argp) {
113 /* Note: it seems Grub transparently decompresses all compressed files,
114 not just the primary kernel. */
115 printf("Loading %s... ", *argp);
116 rv = zloadfile(*argp, &mp->data, &mp->len);
117
118 if (rv) {
119 printf("failed!\n");
120 return -1;
121 }
122 printf("ok\n");
123
124 /*
125 * Note: Grub includes the kernel filename in the command line, so we
126 * want to match that behavior.
127 */
128 arglen = 0;
129 for (argx = argp; *argx && strcmp(*argx, module_separator); argx++)
130 arglen += strlen(*argx) + 1;
131
132 if (arglen == 0) {
133 mp->cmdline = strdup("");
134 } else {
135 char *p;
136 mp->cmdline = p = malloc(arglen);
137 for (; *argp && strcmp(*argp, module_separator); argp++) {
138 p = stpcpy(p, *argp);
139 *p++ = ' ';
140 }
141 *--p = '\0';
142 }
143 mp++;
144 if (*argp)
145 argp++; /* Advance past module_separator */
146 }
147
148 return module_count;
149 }
150
main(int argc,char * argv[])151 int main(int argc, char *argv[])
152 {
153 int nmodules;
154 struct module_data *modules;
155 struct multiboot_header *mbh;
156 bool keeppxe = false;
157
158 openconsole(&dev_null_r, &dev_stdcon_w);
159
160 (void)argc; /* Unused */
161 argv++;
162
163 while (*argv) {
164 bool v = true;
165 const char *p = *argv;
166
167 if (!memcmp(p, "-no", 3)) {
168 v = false;
169 p += 3;
170 }
171
172 if (!strcmp(p, "-solaris")) {
173 opt.solaris = v;
174 set.solaris = true;
175 } else if (!strcmp(p, "-aout")) {
176 opt.aout = v;
177 set.aout = true;
178 } else
179 break;
180 argv++;
181 }
182
183 if (!*argv) {
184 error
185 ("Usage: mboot.c32 [opts] mboot_file args... [--- module args...]...\n"
186 "Options:\n"
187 " -solaris Enable Solaris DHCP information passing\n"
188 " -aout Use the \"a.out kludge\" if enabled, even for ELF\n"
189 " This matches the Multiboot spec, but differs from Grub\n");
190 return 1;
191 }
192
193 /* Load the files */
194 nmodules = get_modules(argv, &modules);
195 if (nmodules < 1) {
196 error("No files found!\n");
197 return 1; /* Failure */
198 }
199
200 if (init_map())
201 return 1; /* Failed to allocate initial map */
202
203 /*
204 * Map the primary image. This should be done before mapping anything
205 * else, since it will have fixed address requirements.
206 */
207 mbh = map_image(modules[0].data, modules[0].len);
208 if (!mbh)
209 return 1;
210
211 /* Map the mbinfo structure */
212 regs.ebx = map_data(&mbinfo, sizeof mbinfo, 4, 0);
213 if (!regs.ebx) {
214 error("Failed to map Multiboot info structure!\n");
215 return 1;
216 }
217
218 /* Map the primary command line */
219 if (modules[0].cmdline) {
220 mbinfo.cmdline = map_string(modules[0].cmdline);
221 dprintf("Main cmdline: \"%s\"\n", modules[0].cmdline);
222 if (mbinfo.cmdline)
223 mbinfo.flags |= MB_INFO_CMDLINE;
224 }
225
226 /* Map auxilliary images */
227 if (nmodules > 1) {
228 if (map_modules(modules + 1, nmodules - 1))
229 return 1;
230 }
231
232 /* Add auxilliary information */
233 mboot_make_memmap();
234 mboot_apm();
235 mboot_syslinux_info();
236
237 if (opt.solaris)
238 mboot_solaris_dhcp_hack();
239
240 /* Set the graphics mode if requested */
241 set_graphics_mode(mbh, &mbinfo);
242
243 /* Run it */
244 mboot_run(keeppxe ? 3 : 0);
245 error("mboot.c32: boot failed\n");
246 return 1;
247 }
248