xref: /netbsd/sys/arch/i386/i386/multiboot.c (revision 6550d01e)
1 /*	$NetBSD: multiboot.c,v 1.21 2011/01/11 12:24:37 gsutre 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.21 2011/01/11 12:24:37 gsutre 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 multiboot_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 multiboot_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 multiboot_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 multiboot_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 multiboot_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), 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 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 != '\0' && *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 multiboot_ksyms_addsyms_elf(void)
689 {
690 	struct multiboot_info *mi = &Multiboot_Info;
691 	struct multiboot_symbols *ms = &Multiboot_Symbols;
692 
693 	if (mi->mi_flags & MULTIBOOT_INFO_HAS_ELF_SYMS) {
694 		Elf32_Ehdr ehdr;
695 
696 		KASSERT(esym != 0);
697 
698 		memcpy(ehdr.e_ident, ELFMAG, SELFMAG);
699 		ehdr.e_ident[EI_CLASS] = ELFCLASS32;
700 		ehdr.e_ident[EI_DATA] = ELFDATA2LSB;
701 		ehdr.e_ident[EI_VERSION] = EV_CURRENT;
702 		ehdr.e_type = ET_EXEC;
703 		ehdr.e_machine = EM_386;
704 		ehdr.e_version = 1;
705 		ehdr.e_ehsize = sizeof(ehdr);
706 
707 		ksyms_addsyms_explicit((void *)&ehdr,
708 		    ms->s_symstart, ms->s_symsize,
709 		    ms->s_strstart, ms->s_strsize);
710 	}
711 
712 	return mi->mi_flags & MULTIBOOT_INFO_HAS_ELF_SYMS;
713 }
714