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 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 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 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