Home | History | Annotate | Download | only in mboot
      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