[BACK]Return to multiboot.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / arch / i386 / i386

File: [cvs.NetBSD.org] / src / sys / arch / i386 / i386 / multiboot.c (download)

Revision 1.8, Wed Oct 25 13:56:16 2006 UTC (17 years, 4 months ago) by jmmv
Branch: MAIN
Changes since 1.7: +94 -129 lines

Remove the usage of Multiboot's "a.out kludge" to tell the boot loader to
reserve some more space for the BSS section than the binary says.  This
trick was used to leave room after the kernel's image to copy the symbol
table following the format required by ksyms_init.  (It was also used to
workaround a bug in the physical address fields of the binary, but this has
been long fixed.)  Yes, the MULTIBOOT_SYMTAB_SPACE option goes away; yay!

Instead, copy the required data after the kernel in a way that avoids having
to reserve space and use the new ksyms_init_explicit function to avoid the
need to construct a minimal ELF image.

Fixes ksyms when using an "unpatched" GRUB (one that does not contain the
fix to honour the "a.out kludge" for ELF images, even when present) -- i.e.
ddb and lkms.  As a side effect, the new code is much clearer to read and
digest.

Closes PR port-i386/32865.

/*	$NetBSD: multiboot.c,v 1.8 2006/10/25 13:56:16 jmmv Exp $	*/

/*-
 * Copyright (c) 2005, 2006 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Julio M. Merino Vidal.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed by the NetBSD
 *	Foundation, Inc. and its contributors.
 * 4. Neither the name of The NetBSD Foundation nor the names of its
 *    contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: multiboot.c,v 1.8 2006/10/25 13:56:16 jmmv Exp $");

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/cdefs_elf.h>
#include <sys/boot_flag.h>
#include <sys/exec.h>
#include <sys/exec_elf.h>
#include <sys/optstr.h>
#include <sys/ksyms.h>

#include <machine/bootinfo.h>
#include <machine/multiboot.h>

#if !defined(MULTIBOOT)
#  error "MULTIBOOT not defined; this cannot happen."
#endif

/* --------------------------------------------------------------------- */

/*
 * Symbol and string table for the loaded kernel.
 */

struct multiboot_symbols {
	caddr_t		s_symstart;
	size_t		s_symsize;
	caddr_t		s_strstart;
	size_t		s_strsize;
};

/* --------------------------------------------------------------------- */

/*
 * External variables.  All of them, with the exception of 'end', must
 * be set at some point within this file.
 *
 * XXX these should be found in a header file!
 */
extern int		biosbasemem;
extern int		biosextmem;
extern int		biosmem_implicit;
extern int		boothowto;
extern struct bootinfo	bootinfo;
extern int		end;
extern int *		esym;

/* --------------------------------------------------------------------- */

/*
 * Copy of the Multiboot information structure passed to us by the boot
 * loader.  The Multiboot_Info structure has some pointers adjusted to the
 * other variables -- see multiboot_pre_reloc() -- so you oughtn't access
 * them directly.  In other words, always access them through the
 * Multiboot_Info variable.
 */
static char			Multiboot_Cmdline[255];
static uint8_t			Multiboot_Drives[255];
static struct multiboot_info	Multiboot_Info;
static boolean_t		Multiboot_Loader = FALSE;
static char			Multiboot_Loader_Name[255];
static uint8_t			Multiboot_Mmap[1024];
static struct multiboot_symbols	Multiboot_Symbols;

/* --------------------------------------------------------------------- */

/*
 * Prototypes for private functions.
 */
static void	bootinfo_add(struct btinfo_common *, int, int);
static void	copy_syms(struct multiboot_info *);
static void	setup_biosgeom(struct multiboot_info *);
static void	setup_bootdisk(struct multiboot_info *);
static void	setup_bootpath(struct multiboot_info *);
static void	setup_console(struct multiboot_info *);
static void	setup_howto(struct multiboot_info *);
static void	setup_memory(struct multiboot_info *);
static void	setup_memmap(struct multiboot_info *);

/* --------------------------------------------------------------------- */

/*
 * Sets up the kernel if it was booted by a Multiboot-compliant boot
 * loader.  This is executed before the kernel has relocated itself.
 * The main purpose of this function is to copy all the information
 * passed in by the boot loader to a safe place, so that it is available
 * after it has been relocated.
 *
 * WARNING: Because the kernel has not yet relocated itself to KERNBASE,
 * special care has to be taken when accessing memory because absolute
 * addresses (referring to kernel symbols) do not work.  So:
 *
 *     1) Avoid jumps to absolute addresses (such as gotos and switches).
 *     2) To access global variables use their physical address, which
 *        can be obtained using the RELOC macro.
 */
void
multiboot_pre_reloc(struct multiboot_info *mi)
{
#define RELOC(type, x) ((type)((vaddr_t)(x) - KERNBASE))
	struct multiboot_info *midest =
	    RELOC(struct multiboot_info *, &Multiboot_Info);

	*RELOC(boolean_t *, &Multiboot_Loader) = TRUE;
	memcpy(midest, mi, sizeof(Multiboot_Info));

	if (mi->mi_flags & MULTIBOOT_INFO_HAS_CMDLINE) {
		strncpy(RELOC(void *, Multiboot_Cmdline), mi->mi_cmdline,
		    sizeof(Multiboot_Cmdline));
		midest->mi_cmdline = (char *)&Multiboot_Cmdline;
	}

	if (mi->mi_flags & MULTIBOOT_INFO_HAS_LOADER_NAME) {
		strncpy(RELOC(void *, Multiboot_Loader_Name),
		    mi->mi_loader_name, sizeof(Multiboot_Loader_Name));
		midest->mi_loader_name = (char *)&Multiboot_Loader_Name;
	}

	if (mi->mi_flags & MULTIBOOT_INFO_HAS_MMAP) {
		memcpy(RELOC(void *, Multiboot_Mmap),
		    (void *)mi->mi_mmap_addr, mi->mi_mmap_length);
		midest->mi_mmap_addr = (vaddr_t)&Multiboot_Mmap;
	}

	if (mi->mi_flags & MULTIBOOT_INFO_HAS_DRIVES) {
		memcpy(RELOC(void *, Multiboot_Drives),
		    (void *)mi->mi_drives_addr, mi->mi_drives_length);
		midest->mi_drives_addr = (vaddr_t)&Multiboot_Drives;
	}

	copy_syms(mi);
#undef RELOC
}

/* --------------------------------------------------------------------- */

/*
 * Sets up the kernel if it was booted by a Multiboot-compliant boot
 * loader.  This is executed just after the kernel has relocated itself.
 * At this point, executing any kind of code is safe, keeping in mind
 * that no devices have been initialized yet (not even the console!).
 */
void
multiboot_post_reloc(void)
{
	struct multiboot_info *mi;
	
	if (! Multiboot_Loader)
		return;

	mi = &Multiboot_Info;
	bootinfo.bi_nentries = 0;

	setup_memory(mi);
	setup_console(mi);
	setup_howto(mi);
	setup_bootpath(mi);
	setup_biosgeom(mi);
	setup_bootdisk(mi);
	setup_memmap(mi);
}

/* --------------------------------------------------------------------- */

/*
 * Prints a summary of the information collected in the Multiboot
 * information header (if present).  Done as a separate function because
 * the console has to be available.
 */
void
multiboot_print_info(void)
{
	struct multiboot_info *mi = &Multiboot_Info;
	struct multiboot_symbols *ms = &Multiboot_Symbols;

	if (! Multiboot_Loader)
		return;

	printf("multiboot: Information structure flags: 0x%08x\n",
	    mi->mi_flags);

	if (mi->mi_flags & MULTIBOOT_INFO_HAS_LOADER_NAME)
		printf("multiboot: Boot loader: %s\n", mi->mi_loader_name);

	if (mi->mi_flags & MULTIBOOT_INFO_HAS_CMDLINE)
		printf("multiboot: Command line: %s\n", mi->mi_cmdline);

	if (mi->mi_flags & MULTIBOOT_INFO_HAS_MEMORY)
		printf("multiboot: %u KB lower memory, %u KB upper memory\n",
		    mi->mi_mem_lower, mi->mi_mem_upper);

	if (mi->mi_flags & MULTIBOOT_INFO_HAS_ELF_SYMS) {
		KASSERT(esym != 0);
		printf("multiboot: Symbol table at %p, length %d bytes\n",
		    ms->s_symstart, ms->s_symsize);
		printf("multiboot: String table at %p, length %d bytes\n",
		    ms->s_strstart, ms->s_strsize);
	}
}

/* --------------------------------------------------------------------- */

/*
 * Adds the bootinfo entry given in 'item' to the bootinfo tables.
 * Sets the item type to 'type' and its length to 'len'.
 */
static void
bootinfo_add(struct btinfo_common *item, int type, int len)
{
	int i;
	struct bootinfo *bip = (struct bootinfo *)&bootinfo;
	vaddr_t data;

	item->type = type;
	item->len = len;

	data = (vaddr_t)&bip->bi_data;
	for (i = 0; i < bip->bi_nentries; i++) {
		struct btinfo_common *tmp;

		tmp = (struct btinfo_common *)data;
		data += tmp->len;
	}
	if (data + len < (vaddr_t)&bip->bi_data + sizeof(bip->bi_data)) {
		memcpy((void *)data, item, len);
		bip->bi_nentries++;
	}
}

/* --------------------------------------------------------------------- */

/*
 * Copies the symbol table and the strings table passed in by the boot
 * loader after the kernel's image, and sets up 'esym' accordingly so
 * that this data is properly copied into upper memory during relocation.
 *
 * WARNING: This code runs before the kernel has relocated itself.  See
 * the note in multiboot_pre_reloc() for more information.
 */
static void
copy_syms(struct multiboot_info *mi)
{
#define RELOC(type, x) ((type)((vaddr_t)(x) - KERNBASE))
	int i;
	Elf32_Shdr *symtabp, *strtabp;
	struct multiboot_symbols *ms;
	size_t symsize, strsize;
	paddr_t symaddr, straddr;
	paddr_t symstart, strstart;


	/*
	 * Check if the Multiboot information header has symbols or not.
	 */
	if (!(mi->mi_flags & MULTIBOOT_INFO_HAS_ELF_SYMS))
		return;

	ms = RELOC(struct multiboot_symbols *, &Multiboot_Symbols);

	/*
	 * Locate a symbol table and its matching string table in the
	 * section headers passed in by the boot loader.  Set 'symtabp'
	 * and 'strtabp' with pointers to the matching entries.
	 */
	symtabp = strtabp = NULL;
	for (i = 0; i < mi->mi_elfshdr_num && symtabp == NULL &&
	    strtabp == NULL; i++) {
		Elf32_Shdr *shdrp;

		shdrp = &((Elf32_Shdr *)mi->mi_elfshdr_addr)[i];

		if ((shdrp->sh_type & SHT_SYMTAB) &&
		    shdrp->sh_link != SHN_UNDEF) {
			Elf32_Shdr *shdrp2;

			shdrp2 = &((Elf32_Shdr *)mi->mi_elfshdr_addr)
			    [shdrp->sh_link];

			if (shdrp2->sh_type & SHT_STRTAB) {
				symtabp = shdrp;
				strtabp = shdrp2;
			}
		}
	}
	if (symtabp == NULL || strtabp == NULL)
		return;

	symaddr = symtabp->sh_addr;
	straddr = strtabp->sh_addr;
	symsize = symtabp->sh_size;
	strsize = strtabp->sh_size;

	/*
	 * Copy the symbol and string tables just after the kernel's
	 * end address, in this order.  Only the contents of these ELF
	 * sections are copied; headers are discarded.  esym is later
	 * updated to point to the lowest "free" address after the tables
	 * so that they are mapped appropriately when enabling paging.
	 *
	 * We need to be careful to not overwrite valid data doing the
	 * copies, hence all the different cases below.  We can assume
	 * that if the tables start before the kernel's end address,
	 * they will not grow over this address.
	 */
        if ((paddr_t)symtabp < (paddr_t)&end - KERNBASE &&
	    (paddr_t)strtabp < (paddr_t)&end - KERNBASE) {
		symstart = (paddr_t)((vaddr_t)&end - KERNBASE);
		strstart = symstart + symsize;
		memcpy((void *)symstart, (void *)symaddr, symsize);
		memcpy((void *)strstart, (void *)straddr, strsize);
        } else if ((paddr_t)symtabp > (paddr_t)&end - KERNBASE &&
	           (paddr_t)strtabp < (paddr_t)&end - KERNBASE) {
		symstart = (paddr_t)((vaddr_t)&end - KERNBASE);
		strstart = symstart + symsize;
		memcpy((void *)symstart, (void *)symaddr, symsize);
		memcpy((void *)strstart, (void *)straddr, strsize);
        } else if ((paddr_t)symtabp < (paddr_t)&end - KERNBASE &&
	           (paddr_t)strtabp > (paddr_t)&end - KERNBASE) {
		strstart = (paddr_t)((vaddr_t)&end - KERNBASE);
		symstart = strstart + strsize;
		memcpy((void *)strstart, (void *)straddr, strsize);
		memcpy((void *)symstart, (void *)symaddr, symsize);
	} else {
		/* symtabp and strtabp are both over end */
		if ((paddr_t)symtabp < (paddr_t)strtabp) {
			symstart = (paddr_t)((vaddr_t)&end - KERNBASE);
			strstart = symstart + symsize;
			memcpy((void *)symstart, (void *)symaddr, symsize);
			memcpy((void *)strstart, (void *)straddr, strsize);
		} else {
			strstart = (paddr_t)((vaddr_t)&end - KERNBASE);
			symstart = strstart + strsize;
			memcpy((void *)strstart, (void *)straddr, strsize);
			memcpy((void *)symstart, (void *)symaddr, symsize);
		}
	}
	*RELOC(int *, &esym) = (int)(strstart + strsize + KERNBASE);

	ms->s_symstart = (caddr_t)(symstart + KERNBASE);
	ms->s_symsize  = symsize;
	ms->s_strstart = (caddr_t)(strstart + KERNBASE);
	ms->s_strsize  = strsize;
#undef RELOC
}

/* --------------------------------------------------------------------- */

/*
 * Sets up the biosgeom bootinfo structure if the Multiboot information
 * structure provides information about disk drives.
 */
static void
setup_biosgeom(struct multiboot_info *mi)
{
	size_t pos;
	uint8_t bidata[1024];
	struct btinfo_biosgeom *bi;

	if (!(mi->mi_flags & MULTIBOOT_INFO_HAS_DRIVES))
		return;

	memset(bidata, 0, sizeof(bidata));
	bi = (struct btinfo_biosgeom *)bidata;
	pos = 0;

	while (pos < mi->mi_drives_length) {
		struct multiboot_drive *md;
		struct bi_biosgeom_entry bbe;

		md = (struct multiboot_drive *)
		    &((uint8_t *)mi->mi_drives_addr)[pos];

		memset(&bbe, 0, sizeof(bbe));
		bbe.sec = md->md_sectors;
		bbe.head = md->md_heads;
		bbe.cyl = md->md_cylinders;
		bbe.dev = md->md_number;

		memcpy(&bi->disk[bi->num], &bbe, sizeof(bbe));
		bi->num++;

		pos += md->md_length;
	}

	bootinfo_add((struct btinfo_common *)bi, BTINFO_BIOSGEOM,
	    sizeof(struct btinfo_biosgeom) +
	    bi->num * sizeof(struct bi_biosgeom_entry));
}

/* --------------------------------------------------------------------- */

/*
 * Sets up the default root device if the Multiboot information
 * structure provides information about the boot drive (where the kernel
 * image was loaded from) or if the user gave a 'root' parameter on the
 * boot command line.
 */
static void
setup_bootdisk(struct multiboot_info *mi)
{
	boolean_t found;
	struct btinfo_rootdevice bi;

	found = FALSE;

	if (mi->mi_flags & MULTIBOOT_INFO_HAS_CMDLINE)
		found = optstr_get(mi->mi_cmdline, "root", bi.devname,
		    sizeof(bi.devname));

	if (!found && (mi->mi_flags & MULTIBOOT_INFO_HAS_BOOT_DEVICE)) {
		const char *devprefix;

		/* Attempt to match the BIOS boot disk to a device.  There
		 * is not much we can do to get it right.  (Well, strictly
		 * speaking, we could, but it is certainly not worth the
		 * extra effort.) */
		switch (mi->mi_boot_device_drive) {
		case 0x00:	devprefix = "fd0";	break;
		case 0x01:	devprefix = "fd1";	break;
		case 0x80:	devprefix = "wd0";	break;
		case 0x81:	devprefix = "wd1";	break;
		case 0x82:	devprefix = "wd2";	break;
		case 0x83:	devprefix = "wd3";	break;
		default:	devprefix = "wd0";
		}

		strcpy(bi.devname, devprefix);
		if (mi->mi_boot_device_part2 != 0xFF)
			bi.devname[3] = mi->mi_boot_device_part2 + 'a';
		else
			bi.devname[3] = 'a';
		bi.devname[4] = '\0';

		found = TRUE;
	}

	if (found) {
		bootinfo_add((struct btinfo_common *)&bi, BTINFO_ROOTDEVICE,
		    sizeof(struct btinfo_rootdevice));
	}
}

/* --------------------------------------------------------------------- */

/*
 * Sets up the bootpath bootinfo structure with an appropriate kernel
 * name derived from the boot command line.  The Multiboot information
 * structure does not provide this detail directly, so we try to derive
 * it from the command line setting.
 */
static void
setup_bootpath(struct multiboot_info *mi)
{
	struct btinfo_bootpath bi;
	char *cl, *cl2, old;
	int len;

	if (strncmp(Multiboot_Loader_Name, "GNU GRUB ",
	    sizeof(Multiboot_Loader_Name)) > 0) {
		cl = mi->mi_cmdline;
		while (*cl != '\0' && *cl != '/')
			cl++;
		cl2 = cl;
		len = 0;
		while (*cl2 != '\0' && *cl2 != ' ') {
			len++;
			cl2++;
		}

		old = *cl2;
		*cl2 = '\0';
		memcpy(bi.bootpath, cl, MIN(sizeof(bi.bootpath), len));
		*cl2 = old;
		bi.bootpath[MIN(sizeof(bi.bootpath), len)] = '\0';

		bootinfo_add((struct btinfo_common *)&bi, BTINFO_BOOTPATH,
		    sizeof(struct btinfo_bootpath));
	}
}

/* --------------------------------------------------------------------- */

/*
 * Sets up the console bootinfo structure if the user gave a 'console'
 * argument on the boot command line.  The Multiboot information
 * structure gives no hint about this, so the only way to know where the
 * console is is to let the user specify it.
 *
 * If there wasn't any 'console' argument, this does not generate any
 * bootinfo entry, falling back to the kernel's default console.
 *
 * If there weren't any of 'console_speed' or 'console_addr' arguments,
 * this falls back to the default values for the serial port.
 */
static void
setup_console(struct multiboot_info *mi)
{
	struct btinfo_console bi;
	boolean_t found;

	found = FALSE;

	if (mi->mi_flags & MULTIBOOT_INFO_HAS_CMDLINE)
		found = optstr_get(mi->mi_cmdline, "console", bi.devname,
		    sizeof(bi.devname));

	if (found) {
		if (strncmp(bi.devname, "com", sizeof(bi.devname)) == 0) {
			char tmp[10];

			found = optstr_get(mi->mi_cmdline, "console_speed",
			    tmp, sizeof(tmp));
			if (found)
				bi.speed = strtoul(tmp, NULL, 10);
			else
				bi.speed = 0; /* Use default speed. */

			found = optstr_get(mi->mi_cmdline, "console_addr",
			    tmp, sizeof(tmp));
			if (found) {
				if (tmp[0] == '0' && tmp[1] == 'x')
					bi.addr = strtoul(tmp + 2, NULL, 16);
				else
					bi.addr = strtoul(tmp, NULL, 10);
			} else
				bi.addr = 0; /* Use default address. */
		}

		bootinfo_add((struct btinfo_common *)&bi, BTINFO_CONSOLE,
		    sizeof(struct btinfo_console));
	}
}

/* --------------------------------------------------------------------- */

/*
 * Sets up the 'boothowto' variable based on the options given in the
 * boot command line, if any.
 */
static void
setup_howto(struct multiboot_info *mi)
{
	char *cl;

	if (!(mi->mi_flags & MULTIBOOT_INFO_HAS_CMDLINE))
		return;

	cl = mi->mi_cmdline;

	/* Skip kernel file name. */
	while (*cl != '\0' && *cl != ' ')
		cl++;
	while (*cl != '\0' && *cl == ' ')
		cl++;

	/* Check if there are flags and set 'howto' accordingly. */
	if (*cl == '-') {
		int howto = 0;

		cl++;
		while (*cl != '\0' && *cl != ' ') {
			BOOT_FLAG(*cl, howto);
			cl++;
		}
		if (*cl == ' ')
			cl++;

		boothowto = howto;
	}
}

/* --------------------------------------------------------------------- */

/*
 * Sets up the memmap bootinfo structure to describe available memory as
 * given by the BIOS.
 */
static void
setup_memmap(struct multiboot_info *mi)
{
	char data[1024];
	size_t i;
	struct btinfo_memmap *bi;

	if (!(mi->mi_flags & MULTIBOOT_INFO_HAS_MMAP))
		return;

	bi = (struct btinfo_memmap *)data;
	bi->num = 0;

	i = 0;
	while (i < mi->mi_mmap_length) {
		struct multiboot_mmap *mm;
		struct bi_memmap_entry *bie;

		bie = &bi->entry[bi->num];

		mm = (struct multiboot_mmap *)(mi->mi_mmap_addr + i);
		bie->addr = mm->mm_base_addr;
		bie->size = mm->mm_length;
		if (mm->mm_type == 1)
			bie->type = BIM_Memory;
		else
			bie->type = BIM_Reserved;

		bi->num++;
		i += mm->mm_size + 4;
	}

	bootinfo_add((struct btinfo_common *)bi, BTINFO_MEMMAP,
	    sizeof(data));
}

/* --------------------------------------------------------------------- */

/*
 * Sets up the 'biosbasemem' and 'biosextmem' variables if the
 * Multiboot information structure provides information about memory.
 */
static void
setup_memory(struct multiboot_info *mi)
{

	if (!(mi->mi_flags & MULTIBOOT_INFO_HAS_MEMORY))
		return;

	/* Make sure we don't override user-set variables. */
	if (biosbasemem == 0) {
		biosbasemem = mi->mi_mem_lower;
		biosmem_implicit = 1;
	}
	if (biosextmem == 0) {
		biosextmem = mi->mi_mem_upper;
		biosmem_implicit = 1;
	}
}

/* --------------------------------------------------------------------- */

/*
 * Sets up the initial kernel symbol table.  Returns true if this was
 * passed in by Multiboot; false otherwise.
 */
boolean_t
multiboot_ksyms_init(void)
{
	struct multiboot_info *mi = &Multiboot_Info;
	struct multiboot_symbols *ms = &Multiboot_Symbols;

	if (mi->mi_flags & MULTIBOOT_INFO_HAS_ELF_SYMS) {
		KASSERT(esym != 0);

		ksyms_init_explicit(ms->s_symstart, ms->s_symsize,
		    ms->s_strstart, ms->s_strsize);
	}

	return mi->mi_flags & MULTIBOOT_INFO_HAS_ELF_SYMS;
}