Home | History | Annotate | Line # | Download | only in i386
      1 /*	$NetBSD: multiboot.c,v 1.26 2019/10/18 01:38:28 manu Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2005, 2006 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Julio M. Merino Vidal.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  * POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 #include <sys/cdefs.h>
     33 __KERNEL_RCSID(0, "$NetBSD: multiboot.c,v 1.26 2019/10/18 01:38:28 manu Exp $");
     34 
     35 #include "opt_multiboot.h"
     36 
     37 #include <sys/param.h>
     38 #include <sys/systm.h>
     39 #include <sys/cdefs_elf.h>
     40 #include <sys/boot_flag.h>
     41 #include <sys/exec.h>
     42 #include <sys/exec_elf.h>
     43 #include <sys/optstr.h>
     44 #include <sys/ksyms.h>
     45 
     46 #include <machine/bootinfo.h>
     47 #include <machine/multiboot.h>
     48 
     49 #if !defined(MULTIBOOT)
     50 #  error "MULTIBOOT not defined; this cannot happen."
     51 #endif
     52 
     53 /* --------------------------------------------------------------------- */
     54 
     55 /*
     56  * Symbol and string table for the loaded kernel.
     57  */
     58 
     59 struct multiboot_symbols {
     60 	void *		s_symstart;
     61 	size_t		s_symsize;
     62 	void *		s_strstart;
     63 	size_t		s_strsize;
     64 };
     65 
     66 /* --------------------------------------------------------------------- */
     67 
     68 /*
     69  * External variables.  All of them, with the exception of 'end', must
     70  * be set at some point within this file.
     71  *
     72  * XXX these should be found in a header file!
     73  */
     74 extern int		biosbasemem;
     75 extern int		biosextmem;
     76 extern int		biosmem_implicit;
     77 extern int		boothowto;
     78 extern struct bootinfo	bootinfo;
     79 extern int		end;
     80 extern int *		esym;
     81 
     82 /* --------------------------------------------------------------------- */
     83 
     84 /*
     85  * Copy of the Multiboot information structure passed to us by the boot
     86  * loader.  The Multiboot_Info structure has some pointers adjusted to the
     87  * other variables -- see multiboot1_pre_reloc() -- so you oughtn't access
     88  * them directly.  In other words, always access them through the
     89  * Multiboot_Info variable.
     90  */
     91 static char			Multiboot_Cmdline[255];
     92 static uint8_t			Multiboot_Drives[255];
     93 static struct multiboot_info	Multiboot_Info;
     94 static bool			Multiboot_Loader = false;
     95 static char			Multiboot_Loader_Name[255];
     96 static uint8_t			Multiboot_Mmap[1024];
     97 static struct multiboot_symbols	Multiboot_Symbols;
     98 
     99 /* --------------------------------------------------------------------- */
    100 
    101 /*
    102  * Prototypes for private functions.
    103  */
    104 static void	bootinfo_add(struct btinfo_common *, int, int);
    105 static void	copy_syms(struct multiboot_info *);
    106 static void	setup_biosgeom(struct multiboot_info *);
    107 static void	setup_bootdisk(struct multiboot_info *);
    108 static void	setup_bootpath(struct multiboot_info *);
    109 static void	setup_console(struct multiboot_info *);
    110 static void	setup_howto(struct multiboot_info *);
    111 static void	setup_memory(struct multiboot_info *);
    112 static void	setup_memmap(struct multiboot_info *);
    113 
    114 /* --------------------------------------------------------------------- */
    115 
    116 /*
    117  * Sets up the kernel if it was booted by a Multiboot-compliant boot
    118  * loader.  This is executed before the kernel has relocated itself.
    119  * The main purpose of this function is to copy all the information
    120  * passed in by the boot loader to a safe place, so that it is available
    121  * after it has been relocated.
    122  *
    123  * WARNING: Because the kernel has not yet relocated itself to KERNBASE,
    124  * special care has to be taken when accessing memory because absolute
    125  * addresses (referring to kernel symbols) do not work.  So:
    126  *
    127  *     1) Avoid jumps to absolute addresses (such as gotos and switches).
    128  *     2) To access global variables use their physical address, which
    129  *        can be obtained using the RELOC macro.
    130  */
    131 void
    132 multiboot1_pre_reloc(struct multiboot_info *mi)
    133 {
    134 #define RELOC(type, x) ((type)((vaddr_t)(x) - KERNBASE))
    135 	struct multiboot_info *midest =
    136 	    RELOC(struct multiboot_info *, &Multiboot_Info);
    137 
    138 	*RELOC(bool *, &Multiboot_Loader) = true;
    139 	memcpy(midest, mi, sizeof(Multiboot_Info));
    140 
    141 	if (mi->mi_flags & MULTIBOOT_INFO_HAS_CMDLINE) {
    142 		strncpy(RELOC(void *, Multiboot_Cmdline), mi->mi_cmdline,
    143 		    sizeof(Multiboot_Cmdline));
    144 		midest->mi_cmdline = (char *)&Multiboot_Cmdline;
    145 	}
    146 
    147 	if (mi->mi_flags & MULTIBOOT_INFO_HAS_LOADER_NAME) {
    148 		strncpy(RELOC(void *, Multiboot_Loader_Name),
    149 		    mi->mi_loader_name, sizeof(Multiboot_Loader_Name));
    150 		midest->mi_loader_name = (char *)&Multiboot_Loader_Name;
    151 	}
    152 
    153 	if (mi->mi_flags & MULTIBOOT_INFO_HAS_MMAP) {
    154 		memcpy(RELOC(void *, Multiboot_Mmap),
    155 		    (void *)mi->mi_mmap_addr, mi->mi_mmap_length);
    156 		midest->mi_mmap_addr = (vaddr_t)&Multiboot_Mmap;
    157 	}
    158 
    159 	if (mi->mi_flags & MULTIBOOT_INFO_HAS_DRIVES) {
    160 		memcpy(RELOC(void *, Multiboot_Drives),
    161 		    (void *)mi->mi_drives_addr, mi->mi_drives_length);
    162 		midest->mi_drives_addr = (vaddr_t)&Multiboot_Drives;
    163 	}
    164 
    165 	copy_syms(mi);
    166 #undef RELOC
    167 }
    168 
    169 /* --------------------------------------------------------------------- */
    170 
    171 /*
    172  * Sets up the kernel if it was booted by a Multiboot-compliant boot
    173  * loader.  This is executed just after the kernel has relocated itself.
    174  * At this point, executing any kind of code is safe, keeping in mind
    175  * that no devices have been initialized yet (not even the console!).
    176  */
    177 void
    178 multiboot1_post_reloc(void)
    179 {
    180 	struct multiboot_info *mi;
    181 
    182 	if (! Multiboot_Loader)
    183 		return;
    184 
    185 	mi = &Multiboot_Info;
    186 	bootinfo.bi_nentries = 0;
    187 
    188 	setup_memory(mi);
    189 	setup_console(mi);
    190 	setup_howto(mi);
    191 	setup_bootpath(mi);
    192 	setup_biosgeom(mi);
    193 	setup_bootdisk(mi);
    194 	setup_memmap(mi);
    195 }
    196 
    197 /* --------------------------------------------------------------------- */
    198 
    199 /*
    200  * Prints a summary of the information collected in the Multiboot
    201  * information header (if present).  Done as a separate function because
    202  * the console has to be available.
    203  */
    204 void
    205 multiboot1_print_info(void)
    206 {
    207 	struct multiboot_info *mi = &Multiboot_Info;
    208 	struct multiboot_symbols *ms = &Multiboot_Symbols;
    209 
    210 	if (! Multiboot_Loader)
    211 		return;
    212 
    213 	printf("multiboot: Information structure flags: 0x%08x\n",
    214 	    mi->mi_flags);
    215 
    216 	if (mi->mi_flags & MULTIBOOT_INFO_HAS_LOADER_NAME)
    217 		printf("multiboot: Boot loader: %s\n", mi->mi_loader_name);
    218 
    219 	if (mi->mi_flags & MULTIBOOT_INFO_HAS_CMDLINE)
    220 		printf("multiboot: Command line: %s\n", mi->mi_cmdline);
    221 
    222 	if (mi->mi_flags & MULTIBOOT_INFO_HAS_MEMORY)
    223 		printf("multiboot: %u KB lower memory, %u KB upper memory\n",
    224 		    mi->mi_mem_lower, mi->mi_mem_upper);
    225 
    226 	if (mi->mi_flags & MULTIBOOT_INFO_HAS_ELF_SYMS) {
    227 		KASSERT(esym != 0);
    228 		printf("multiboot: Symbol table at %p, length %d bytes\n",
    229 		    ms->s_symstart, ms->s_symsize);
    230 		printf("multiboot: String table at %p, length %d bytes\n",
    231 		    ms->s_strstart, ms->s_strsize);
    232 	}
    233 }
    234 
    235 /* --------------------------------------------------------------------- */
    236 
    237 /*
    238  * Adds the bootinfo entry given in 'item' to the bootinfo tables.
    239  * Sets the item type to 'type' and its length to 'len'.
    240  */
    241 static void
    242 bootinfo_add(struct btinfo_common *item, int type, int len)
    243 {
    244 	int i;
    245 	struct bootinfo *bip = (struct bootinfo *)&bootinfo;
    246 	vaddr_t data;
    247 
    248 	item->type = type;
    249 	item->len = len;
    250 
    251 	data = (vaddr_t)&bip->bi_data;
    252 	for (i = 0; i < bip->bi_nentries; i++) {
    253 		struct btinfo_common *tmp;
    254 
    255 		tmp = (struct btinfo_common *)data;
    256 		data += tmp->len;
    257 	}
    258 	if (data + len < (vaddr_t)&bip->bi_data + sizeof(bip->bi_data)) {
    259 		memcpy((void *)data, item, len);
    260 		bip->bi_nentries++;
    261 	}
    262 }
    263 
    264 /* --------------------------------------------------------------------- */
    265 
    266 /*
    267  * Copies the symbol table and the strings table passed in by the boot
    268  * loader after the kernel's image, and sets up 'esym' accordingly so
    269  * that this data is properly copied into upper memory during relocation.
    270  *
    271  * WARNING: This code runs before the kernel has relocated itself.  See
    272  * the note in multiboot1_pre_reloc() for more information.
    273  */
    274 static void
    275 copy_syms(struct multiboot_info *mi)
    276 {
    277 #define RELOC(type, x) ((type)((vaddr_t)(x) - KERNBASE))
    278 	int i;
    279 	struct multiboot_symbols *ms;
    280 	Elf32_Shdr *symtabp, *strtabp;
    281 	Elf32_Word symsize, strsize;
    282 	Elf32_Addr symaddr, straddr;
    283 	Elf32_Addr symstart, strstart;
    284 
    285 	/*
    286 	 * Check if the Multiboot information header has symbols or not.
    287 	 */
    288 	if (!(mi->mi_flags & MULTIBOOT_INFO_HAS_ELF_SYMS))
    289 		return;
    290 
    291 	ms = RELOC(struct multiboot_symbols *, &Multiboot_Symbols);
    292 
    293 	/*
    294 	 * Locate a symbol table and its matching string table in the
    295 	 * section headers passed in by the boot loader.  Set 'symtabp'
    296 	 * and 'strtabp' with pointers to the matching entries.
    297 	 */
    298 	symtabp = strtabp = NULL;
    299 	for (i = 0; i < mi->mi_elfshdr_num && symtabp == NULL &&
    300 	    strtabp == NULL; i++) {
    301 		Elf32_Shdr *shdrp;
    302 
    303 		shdrp = &((Elf32_Shdr *)mi->mi_elfshdr_addr)[i];
    304 
    305 		if ((shdrp->sh_type == SHT_SYMTAB) &&
    306 		    shdrp->sh_link != SHN_UNDEF) {
    307 			Elf32_Shdr *shdrp2;
    308 
    309 			shdrp2 = &((Elf32_Shdr *)mi->mi_elfshdr_addr)
    310 			    [shdrp->sh_link];
    311 
    312 			if (shdrp2->sh_type == SHT_STRTAB) {
    313 				symtabp = shdrp;
    314 				strtabp = shdrp2;
    315 			}
    316 		}
    317 	}
    318 	if (symtabp == NULL || strtabp == NULL)
    319 		return;
    320 
    321 	symaddr = symtabp->sh_addr;
    322 	straddr = strtabp->sh_addr;
    323 	symsize = symtabp->sh_size;
    324 	strsize = strtabp->sh_size;
    325 
    326 	/*
    327 	 * Copy the symbol and string tables just after the kernel's
    328 	 * end address, in this order.  Only the contents of these ELF
    329 	 * sections are copied; headers are discarded.  esym is later
    330 	 * updated to point to the lowest "free" address after the tables
    331 	 * so that they are mapped appropriately when enabling paging.
    332 	 *
    333 	 * We need to be careful to not overwrite valid data doing the
    334 	 * copies, hence all the different cases below.  We can assume
    335 	 * that if the tables start before the kernel's end address,
    336 	 * they will not grow over this address.
    337 	 */
    338         if ((void *)symtabp < RELOC(void *, &end) &&
    339 	    (void *)strtabp < RELOC(void *, &end)) {
    340 		symstart = RELOC(Elf32_Addr, &end);
    341 		strstart = symstart + symsize;
    342 		memcpy((void *)symstart, (void *)symaddr, symsize);
    343 		memcpy((void *)strstart, (void *)straddr, strsize);
    344         } else if ((void *)symtabp > RELOC(void *, &end) &&
    345 	           (void *)strtabp < RELOC(void *, &end)) {
    346 		symstart = RELOC(Elf32_Addr, &end);
    347 		strstart = symstart + symsize;
    348 		memcpy((void *)symstart, (void *)symaddr, symsize);
    349 		memcpy((void *)strstart, (void *)straddr, strsize);
    350         } else if ((void *)symtabp < RELOC(void *, &end) &&
    351 	           (void *)strtabp > RELOC(void *, &end)) {
    352 		strstart = RELOC(Elf32_Addr, &end);
    353 		symstart = strstart + strsize;
    354 		memcpy((void *)strstart, (void *)straddr, strsize);
    355 		memcpy((void *)symstart, (void *)symaddr, symsize);
    356 	} else {
    357 		/* symtabp and strtabp are both over end */
    358 		if (symtabp < strtabp) {
    359 			symstart = RELOC(Elf32_Addr, &end);
    360 			strstart = symstart + symsize;
    361 			memcpy((void *)symstart, (void *)symaddr, symsize);
    362 			memcpy((void *)strstart, (void *)straddr, strsize);
    363 		} else {
    364 			strstart = RELOC(Elf32_Addr, &end);
    365 			symstart = strstart + strsize;
    366 			memcpy((void *)strstart, (void *)straddr, strsize);
    367 			memcpy((void *)symstart, (void *)symaddr, symsize);
    368 		}
    369 	}
    370 
    371 	*RELOC(int *, &esym) =
    372 	    (int)(symstart + symsize + strsize + KERNBASE);
    373 
    374 	ms->s_symstart = (void *)(symstart + KERNBASE);
    375 	ms->s_symsize  = symsize;
    376 	ms->s_strstart = (void *)(strstart + KERNBASE);
    377 	ms->s_strsize  = strsize;
    378 #undef RELOC
    379 }
    380 
    381 /* --------------------------------------------------------------------- */
    382 
    383 /*
    384  * Sets up the biosgeom bootinfo structure if the Multiboot information
    385  * structure provides information about disk drives.
    386  */
    387 static void
    388 setup_biosgeom(struct multiboot_info *mi)
    389 {
    390 	size_t pos;
    391 	uint8_t bidata[1024];
    392 	struct btinfo_biosgeom *bi;
    393 
    394 	if (!(mi->mi_flags & MULTIBOOT_INFO_HAS_DRIVES))
    395 		return;
    396 
    397 	memset(bidata, 0, sizeof(bidata));
    398 	bi = (struct btinfo_biosgeom *)bidata;
    399 	pos = 0;
    400 
    401 	while (pos < mi->mi_drives_length) {
    402 		struct multiboot_drive *md;
    403 		struct bi_biosgeom_entry bbe;
    404 
    405 		md = (struct multiboot_drive *)
    406 		    &((uint8_t *)mi->mi_drives_addr)[pos];
    407 
    408 		memset(&bbe, 0, sizeof(bbe));
    409 		bbe.sec = md->md_sectors;
    410 		bbe.head = md->md_heads;
    411 		bbe.cyl = md->md_cylinders;
    412 		bbe.dev = md->md_number;
    413 
    414 		memcpy(&bi->disk[bi->num], &bbe, sizeof(bbe));
    415 		bi->num++;
    416 
    417 		pos += md->md_length;
    418 	}
    419 
    420 	bootinfo_add((struct btinfo_common *)bi, BTINFO_BIOSGEOM,
    421 	    sizeof(struct btinfo_biosgeom) +
    422 	    bi->num * sizeof(struct bi_biosgeom_entry));
    423 }
    424 
    425 /* --------------------------------------------------------------------- */
    426 
    427 /*
    428  * Sets up the default root device if the Multiboot information
    429  * structure provides information about the boot drive (where the kernel
    430  * image was loaded from) or if the user gave a 'root' parameter on the
    431  * boot command line.
    432  */
    433 static void
    434 setup_bootdisk(struct multiboot_info *mi)
    435 {
    436 	bool found;
    437 	struct btinfo_rootdevice bi;
    438 
    439 	found = false;
    440 
    441 	if (mi->mi_flags & MULTIBOOT_INFO_HAS_CMDLINE)
    442 		found = optstr_get(mi->mi_cmdline, "root", bi.devname,
    443 		    sizeof(bi.devname));
    444 
    445 	if (!found && (mi->mi_flags & MULTIBOOT_INFO_HAS_BOOT_DEVICE)) {
    446 		const char *devprefix;
    447 
    448 		/* Attempt to match the BIOS boot disk to a device.  There
    449 		 * is not much we can do to get it right.  (Well, strictly
    450 		 * speaking, we could, but it is certainly not worth the
    451 		 * extra effort.) */
    452 		switch (mi->mi_boot_device_drive) {
    453 		case 0x00:	devprefix = "fd0";	break;
    454 		case 0x01:	devprefix = "fd1";	break;
    455 		case 0x80:	devprefix = "wd0";	break;
    456 		case 0x81:	devprefix = "wd1";	break;
    457 		case 0x82:	devprefix = "wd2";	break;
    458 		case 0x83:	devprefix = "wd3";	break;
    459 		default:	devprefix = "wd0";
    460 		}
    461 
    462 		strcpy(bi.devname, devprefix);
    463 		if (mi->mi_boot_device_part2 != 0xFF)
    464 			bi.devname[3] = mi->mi_boot_device_part2 + 'a';
    465 		else
    466 			bi.devname[3] = 'a';
    467 		bi.devname[4] = '\0';
    468 
    469 		found = true;
    470 	}
    471 
    472 	if (found) {
    473 		bootinfo_add((struct btinfo_common *)&bi, BTINFO_ROOTDEVICE,
    474 		    sizeof(struct btinfo_rootdevice));
    475 	}
    476 }
    477 
    478 /* --------------------------------------------------------------------- */
    479 
    480 /*
    481  * Sets up the bootpath bootinfo structure with an appropriate kernel
    482  * name derived from the boot command line.  The Multiboot information
    483  * structure does not provide this detail directly, so we try to derive
    484  * it from the command line setting.
    485  */
    486 static void
    487 setup_bootpath(struct multiboot_info *mi)
    488 {
    489 	struct btinfo_bootpath bi;
    490 	char *cl, *cl2, old;
    491 	int len;
    492 
    493 	if (strncmp(Multiboot_Loader_Name, "GNU GRUB ",
    494 	    sizeof(Multiboot_Loader_Name)) > 0) {
    495 		cl = mi->mi_cmdline;
    496 		while (*cl != '\0' && *cl != '/')
    497 			cl++;
    498 		cl2 = cl;
    499 		len = 0;
    500 		while (*cl2 != '\0' && *cl2 != ' ') {
    501 			len++;
    502 			cl2++;
    503 		}
    504 
    505 		old = *cl2;
    506 		*cl2 = '\0';
    507 		memcpy(bi.bootpath, cl, MIN(sizeof(bi.bootpath), len));
    508 		*cl2 = old;
    509 		bi.bootpath[MIN(sizeof(bi.bootpath) - 1, len)] = '\0';
    510 
    511 		bootinfo_add((struct btinfo_common *)&bi, BTINFO_BOOTPATH,
    512 		    sizeof(struct btinfo_bootpath));
    513 	}
    514 }
    515 
    516 /* --------------------------------------------------------------------- */
    517 
    518 /*
    519  * Sets up the console bootinfo structure if the user gave a 'console'
    520  * argument on the boot command line.  The Multiboot information
    521  * structure gives no hint about this, so the only way to know where the
    522  * console is to let the user specify it.
    523  *
    524  * If there wasn't any 'console' argument, this does not generate any
    525  * bootinfo entry, falling back to the kernel's default console.
    526  *
    527  * If there weren't any of 'console_speed' or 'console_addr' arguments,
    528  * this falls back to the default values for the serial port.
    529  */
    530 static void
    531 setup_console(struct multiboot_info *mi)
    532 {
    533 	struct btinfo_console bi;
    534 	bool found;
    535 
    536 	found = false;
    537 
    538 	if (mi->mi_flags & MULTIBOOT_INFO_HAS_CMDLINE)
    539 		found = optstr_get(mi->mi_cmdline, "console", bi.devname,
    540 		    sizeof(bi.devname));
    541 
    542 	if (found) {
    543 		bool valid;
    544 
    545 		if (strncmp(bi.devname, "com", sizeof(bi.devname)) == 0) {
    546 			char tmp[10];
    547 
    548 			found = optstr_get(mi->mi_cmdline, "console_speed",
    549 			    tmp, sizeof(tmp));
    550 			if (found)
    551 				bi.speed = strtoul(tmp, NULL, 10);
    552 			else
    553 				bi.speed = 0; /* Use default speed. */
    554 
    555 			found = optstr_get(mi->mi_cmdline, "console_addr",
    556 			    tmp, sizeof(tmp));
    557 			if (found) {
    558 				if (tmp[0] == '0' && tmp[1] == 'x')
    559 					bi.addr = strtoul(tmp + 2, NULL, 16);
    560 				else
    561 					bi.addr = strtoul(tmp, NULL, 10);
    562 			} else
    563 				bi.addr = 0; /* Use default address. */
    564 
    565 			valid = true;
    566 		} else if (strncmp(bi.devname, "pc", sizeof(bi.devname)) == 0)
    567 			valid = true;
    568 		else
    569 			valid = false;
    570 
    571 		if (valid)
    572 			bootinfo_add((struct btinfo_common *)&bi,
    573 			    BTINFO_CONSOLE, sizeof(struct btinfo_console));
    574 	}
    575 }
    576 
    577 /* --------------------------------------------------------------------- */
    578 
    579 /*
    580  * Sets up the 'boothowto' variable based on the options given in the
    581  * boot command line, if any.
    582  */
    583 static void
    584 setup_howto(struct multiboot_info *mi)
    585 {
    586 	char *cl;
    587 
    588 	if (!(mi->mi_flags & MULTIBOOT_INFO_HAS_CMDLINE))
    589 		return;
    590 
    591 	cl = mi->mi_cmdline;
    592 
    593 	/* Skip kernel file name. */
    594 	while (*cl != '\0' && *cl != ' ')
    595 		cl++;
    596 	while (*cl == ' ')
    597 		cl++;
    598 
    599 	/* Check if there are flags and set 'howto' accordingly. */
    600 	if (*cl == '-') {
    601 		int howto = 0;
    602 
    603 		cl++;
    604 		while (*cl != '\0' && *cl != ' ') {
    605 			BOOT_FLAG(*cl, howto);
    606 			cl++;
    607 		}
    608 		if (*cl == ' ')
    609 			cl++;
    610 
    611 		boothowto = howto;
    612 	}
    613 }
    614 
    615 /* --------------------------------------------------------------------- */
    616 
    617 /*
    618  * Sets up the memmap bootinfo structure to describe available memory as
    619  * given by the BIOS.
    620  */
    621 static void
    622 setup_memmap(struct multiboot_info *mi)
    623 {
    624 	char data[1024];
    625 	size_t i;
    626 	struct btinfo_memmap *bi;
    627 
    628 	if (!(mi->mi_flags & MULTIBOOT_INFO_HAS_MMAP))
    629 		return;
    630 
    631 	bi = (struct btinfo_memmap *)data;
    632 	bi->num = 0;
    633 
    634 	i = 0;
    635 	while (i < mi->mi_mmap_length) {
    636 		struct multiboot_mmap *mm;
    637 		struct bi_memmap_entry *bie;
    638 
    639 		bie = &bi->entry[bi->num];
    640 
    641 		mm = (struct multiboot_mmap *)(mi->mi_mmap_addr + i);
    642 		bie->addr = mm->mm_base_addr;
    643 		bie->size = mm->mm_length;
    644 		if (mm->mm_type == 1)
    645 			bie->type = BIM_Memory;
    646 		else
    647 			bie->type = BIM_Reserved;
    648 
    649 		bi->num++;
    650 		i += mm->mm_size + 4;
    651 	}
    652 
    653 	bootinfo_add((struct btinfo_common *)bi, BTINFO_MEMMAP,
    654 	    sizeof(data));
    655 }
    656 
    657 /* --------------------------------------------------------------------- */
    658 
    659 /*
    660  * Sets up the 'biosbasemem' and 'biosextmem' variables if the
    661  * Multiboot information structure provides information about memory.
    662  */
    663 static void
    664 setup_memory(struct multiboot_info *mi)
    665 {
    666 
    667 	if (!(mi->mi_flags & MULTIBOOT_INFO_HAS_MEMORY))
    668 		return;
    669 
    670 	/* Make sure we don't override user-set variables. */
    671 	if (biosbasemem == 0) {
    672 		biosbasemem = mi->mi_mem_lower;
    673 		biosmem_implicit = 1;
    674 	}
    675 	if (biosextmem == 0) {
    676 		biosextmem = mi->mi_mem_upper;
    677 		biosmem_implicit = 1;
    678 	}
    679 }
    680 
    681 /* --------------------------------------------------------------------- */
    682 
    683 /*
    684  * Sets up the initial kernel symbol table.  Returns true if this was
    685  * passed in by Multiboot; false otherwise.
    686  */
    687 bool
    688 multiboot1_ksyms_addsyms_elf(void)
    689 {
    690 	struct multiboot_info *mi = &Multiboot_Info;
    691 	struct multiboot_symbols *ms = &Multiboot_Symbols;
    692 
    693 	if (! Multiboot_Loader)
    694 		return false;
    695 
    696 	if (mi->mi_flags & MULTIBOOT_INFO_HAS_ELF_SYMS) {
    697 		Elf32_Ehdr ehdr;
    698 
    699 		KASSERT(esym != 0);
    700 
    701 		memcpy(ehdr.e_ident, ELFMAG, SELFMAG);
    702 		ehdr.e_ident[EI_CLASS] = ELFCLASS32;
    703 		ehdr.e_ident[EI_DATA] = ELFDATA2LSB;
    704 		ehdr.e_ident[EI_VERSION] = EV_CURRENT;
    705 		ehdr.e_type = ET_EXEC;
    706 		ehdr.e_machine = EM_386;
    707 		ehdr.e_version = 1;
    708 		ehdr.e_ehsize = sizeof(ehdr);
    709 
    710 		ksyms_addsyms_explicit((void *)&ehdr,
    711 		    ms->s_symstart, ms->s_symsize,
    712 		    ms->s_strstart, ms->s_strsize);
    713 	}
    714 
    715 	return mi->mi_flags & MULTIBOOT_INFO_HAS_ELF_SYMS;
    716 }
    717