Implement support for 'The Multiboot Specification' so that i386 kernels trunk
authorjmmv <jmmv@NetBSD.org>
Fri, 03 Feb 2006 11:08:23 +0000
branchtrunk
changeset 143130 93570a1b7c40
parent 143129 323cd2d81234
child 143131 8e79cb82ab72
Implement support for 'The Multiboot Specification' so that i386 kernels can be booted directly from Multiboot-compliant boot loaders (e.g. GRUB). See the added multiboot(8) manual page for more information. No objections in tech-kern@; only positive comments.
distrib/sets/lists/comp/md.i386
distrib/sets/lists/man/mi
doc/CHANGES
share/man/man4/options.4
share/man/man8/man8.i386/Makefile
share/man/man8/man8.i386/multiboot.8
sys/arch/i386/conf/GENERIC
sys/arch/i386/conf/GENERIC_LAPTOP
sys/arch/i386/conf/files.i386
sys/arch/i386/i386/locore.S
sys/arch/i386/i386/machdep.c
sys/arch/i386/i386/multiboot.c
sys/arch/i386/include/Makefile
sys/arch/i386/include/multiboot.h
sys/arch/x86/include/bootinfo.h
sys/arch/x86/x86/consinit.c
sys/arch/x86/x86/x86_autoconf.c
--- a/distrib/sets/lists/comp/md.i386	Fri Feb 03 11:04:46 2006 +0000
+++ b/distrib/sets/lists/comp/md.i386	Fri Feb 03 11:08:23 2006 +0000
@@ -1,4 +1,4 @@
-# $NetBSD: md.i386,v 1.87 2005/05/03 08:24:15 tron Exp $
+# $NetBSD: md.i386,v 1.88 2006/02/03 11:08:23 jmmv Exp $
 ./usr/include/emmintrin.h			comp-c-include		gcccmds
 ./usr/include/i386				comp-c-include
 ./usr/include/i386/_G_config.h			comp-obsolete		obsolete
@@ -45,6 +45,7 @@
 ./usr/include/i386/mcontext.h			comp-c-include
 ./usr/include/i386/mouse.h			comp-obsolete		obsolete
 ./usr/include/i386/mtrr.h			comp-c-include
+./usr/include/i386/multiboot.h			comp-c-include
 ./usr/include/i386/npx.h			comp-c-include
 ./usr/include/i386/param.h			comp-c-include
 ./usr/include/i386/pcb.h			comp-c-include
--- a/distrib/sets/lists/man/mi	Fri Feb 03 11:04:46 2006 +0000
+++ b/distrib/sets/lists/man/mi	Fri Feb 03 11:08:23 2006 +0000
@@ -1,4 +1,4 @@
-# $NetBSD: mi,v 1.849 2006/02/02 15:26:34 reinoud Exp $
+# $NetBSD: mi,v 1.850 2006/02/03 11:08:23 jmmv Exp $
 ./etc/mtree/set.man				man-sys-root
 ./usr/share/info/am-utils.info			man-amd-info		info
 ./usr/share/info/as.info			man-computil-info	bfd,info
@@ -1848,6 +1848,7 @@
 ./usr/share/man/cat8/i386/ispcvt.0		man-obsolete		obsolete
 ./usr/share/man/cat8/i386/kbdio.0		man-obsolete		obsolete
 ./usr/share/man/cat8/i386/makedev.0		man-obsolete		obsolete
+./usr/share/man/cat8/i386/multiboot.0		man-sys-catman		.cat
 ./usr/share/man/cat8/i386/mbr.0			man-sys-catman		.cat
 ./usr/share/man/cat8/i386/pxeboot.0		man-sys-catman		.cat
 ./usr/share/man/cat8/i386/reboot.0		man-obsolete		obsolete
@@ -4147,6 +4148,7 @@
 ./usr/share/man/man8/i386/ispcvt.8		man-obsolete		obsolete
 ./usr/share/man/man8/i386/kbdio.8		man-obsolete		obsolete
 ./usr/share/man/man8/i386/makedev.8		man-obsolete		obsolete
+./usr/share/man/man8/i386/multiboot.8		man-sys-man		.man
 ./usr/share/man/man8/i386/mbr.8			man-sys-man		.man
 ./usr/share/man/man8/i386/pxeboot.8		man-sys-man		.man
 ./usr/share/man/man8/i386/reboot.8		man-obsolete		obsolete
--- a/doc/CHANGES	Fri Feb 03 11:04:46 2006 +0000
+++ b/doc/CHANGES	Fri Feb 03 11:08:23 2006 +0000
@@ -1,4 +1,4 @@
-LIST OF CHANGES FROM LAST RELEASE:			<$Revision: 1.570 $>
+LIST OF CHANGES FROM LAST RELEASE:			<$Revision: 1.571 $>
 
 
 [Note: This file does not mention every change made to the NetBSD source tree.
@@ -178,3 +178,4 @@
 		devices like harddisc partions and vnd's.
 		[reinoud 20060202]
 	binutils: updated to FSF binutils 2.16.1 release.  [skrll 20060202]
+	i386: Add support for the Multiboot Specification.  [jmmv 20060203]
--- a/share/man/man4/options.4	Fri Feb 03 11:04:46 2006 +0000
+++ b/share/man/man4/options.4	Fri Feb 03 11:08:23 2006 +0000
@@ -1,4 +1,4 @@
-.\"	$NetBSD: options.4,v 1.307 2006/02/02 17:35:37 rpaulo Exp $
+.\"	$NetBSD: options.4,v 1.308 2006/02/03 11:08:23 jmmv Exp $
 .\"
 .\" Copyright (c) 1996
 .\" 	Perry E. Metzger.  All rights reserved.
@@ -30,7 +30,7 @@
 .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 .\"
 .\"
-.Dd February 2, 2006
+.Dd February 3, 2006
 .Os
 .Dt OPTIONS 4
 .Sh NAME
@@ -2420,6 +2420,19 @@
 .Cd options BEEP_ONHALT
 is enabled, in milliseconds.
 Defaults to 250.
+.It Cd options MULTIBOOT
+Makes the kernel Multiboot-compliant, allowing it to be booted through
+a Multiboot-compliant boot manager such as GRUB.
+See
+.Xr multiboot 8
+for more information.
+.It Cd options MULTIBOOT_SYMTAB_SPACE=nbytes
+Space (in bytes) reserved in memory to store the kernel's symbol table.
+If the symbol table is bigger than this space, it will not be loaded;
+if it is smaller, the unused memory will be claimed by the kernel and
+used normally.
+You shouldn't need to touch this variable.
+Defaults to 1048576 bytes (one megabyte).
 .El
 .Ss isa-specific Options
 Options specific to
--- a/share/man/man8/man8.i386/Makefile	Fri Feb 03 11:04:46 2006 +0000
+++ b/share/man/man8/man8.i386/Makefile	Fri Feb 03 11:08:23 2006 +0000
@@ -1,7 +1,7 @@
-#	$NetBSD: Makefile,v 1.17 2003/10/24 20:26:58 jdolecek Exp $
+#	$NetBSD: Makefile,v 1.18 2006/02/03 11:08:23 jmmv Exp $
 #	from: @(#)Makefile	8.1 (Berkeley) 6/5/93
 
-MAN=	boot.8 dosboot.8 boot_console.8 w95boot.8 pxeboot.8 mbr.8
+MAN=	boot.8 dosboot.8 boot_console.8 multiboot.8 w95boot.8 pxeboot.8 mbr.8
 MLINKS=	mbr.8 bootselect.8
 MANSUBDIR=/i386
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/share/man/man8/man8.i386/multiboot.8	Fri Feb 03 11:08:23 2006 +0000
@@ -0,0 +1,133 @@
+.\"	$NetBSD: multiboot.8,v 1.1 2006/02/03 11:08:23 jmmv Exp $
+.\"
+.\" Copyright (c) 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.
+.\"
+.Dd Februrary 3, 2006
+.Os
+.Dt MULTIBOOT 8 i386
+.Sh NAME
+.Nm multiboot
+.Nd procedure for booting NetBSD/i386 from a Multiboot-compliant boot loader
+.Sh DESCRIPTION
+Multiboot is a specification that defines a protocol between a boot loader
+and a kernel.
+This protocol allows passing boot information between the two in a standard
+way, allowing any Multiboot-compliant boot loader to boot any
+Multiboot-compliant kernel.
+The
+.Nx
+kernel supports Multiboot if it was compiled with
+.Cd options MULTIBOOT
+(the default in the
+.Sq GENERIC
+and
+.Sq GENERIC_LAPTOP
+configurations).
+.Pp
+Unlike when using the native boot loader, the
+.Nx
+kernel recognizes a set of command line arguments if booted through a
+Multiboot-compliant boot loader.
+This is because the Multiboot protocol is not complete enough to completely
+configure a
+.Nx
+kernel.
+.Pp
+The following arguments are recognized:
+.Bl -tag -width consoleXspeedX
+.It Va console
+Specifies the console device name.
+Can be one of
+.Sq com
+or
+.Sq pc .
+If the former,
+.Va console_addr
+and
+.Va console_speed
+should be given too.
+.It Va console_addr
+Specifies the serial port address for the console.
+Defaults to the value of
+.Cd options CONADDR
+or
+.Sq 0x3f8
+if this was not given.
+.It Va console_speed
+Specifies the serial port speed for the console.
+Defaults to the value of
+.Cd options CONSPEED
+or
+.Sq 9600
+if this was not given.
+.It Va root
+Specifies the name of the device to be mounted as the root partition.
+It should not be needed because the kernel tries its best to guess which
+is the root partition (basing the decision on the device from which the
+kernel was loaded from).
+In cases where the automatic detection fails, this flag comes useful.
+Example:
+.Sq root=wd0e .
+.El
+.Ss Booting with GRUB Legacy
+GRUB Legacy can load Multiboot-enabled
+.Nx
+kernels properly, assuming that a patch which fixes an issue with the
+Multiboot header parsing is applied.
+This patch is not yet merged with the stock sources but is available in
+pkgsrc; hence, if you have
+.Sq grub-0.97nb4
+or a better version, the bug is fixed.
+However, if you are building GRUB Legacy outside pkgsrc, you need to manually
+apply the patch located at:
+.Pa ftp://ftp.NetBSD.org/pub/NetBSD/misc/jmmv/grub-fix-addresses.diff .
+.Pp
+With the patch applied, a
+.Nx
+kernel can be booted using the traditional GRUB Legacy syntax.
+For example:
+.Bd -literal
+kernel (fd0)/netbsd.gz -c console=pc root=wd0e
+.Ed
+.Sh SEE ALSO
+.Xr options 4
+.Sh HISTORY
+.Nm
+support first appeared in
+.Nx 4.0 .
+.Sh AUTHORS
+.Nm
+support was added by
+.An Julio M. Merino Vidal Aq jmmv@NetBSD.org .
--- a/sys/arch/i386/conf/GENERIC	Fri Feb 03 11:04:46 2006 +0000
+++ b/sys/arch/i386/conf/GENERIC	Fri Feb 03 11:08:23 2006 +0000
@@ -1,4 +1,4 @@
-# $NetBSD: GENERIC,v 1.722 2006/02/02 21:32:09 reinoud Exp $
+# $NetBSD: GENERIC,v 1.723 2006/02/03 11:08:23 jmmv Exp $
 #
 # GENERIC machine description file
 #
@@ -22,7 +22,7 @@
 
 options 	INCLUDE_CONFIG_FILE	# embed config file in kernel binary
 
-#ident 		"GENERIC-$Revision: 1.722 $"
+#ident 		"GENERIC-$Revision: 1.723 $"
 
 maxusers	32		# estimated number of users
 
@@ -50,6 +50,9 @@
 # doesn't work with MP just yet..
 #options 	PERFCTRS	# performance-monitoring counters support
 
+options 	MULTIBOOT	# Multiboot support (see multiboot(8))
+#options 	MULTIBOOT_SYMTAB_SPACE=1048576
+
 # delay between "rebooting ..." message and hardware reset, in milliseconds
 #options 	CPURESET_DELAY=2000
 
--- a/sys/arch/i386/conf/GENERIC_LAPTOP	Fri Feb 03 11:04:46 2006 +0000
+++ b/sys/arch/i386/conf/GENERIC_LAPTOP	Fri Feb 03 11:08:23 2006 +0000
@@ -1,4 +1,4 @@
-#	$NetBSD: GENERIC_LAPTOP,v 1.170 2006/02/03 01:09:49 reinoud Exp $
+#	$NetBSD: GENERIC_LAPTOP,v 1.171 2006/02/03 11:08:23 jmmv Exp $
 #	From: NetBSD: GENERIC,v 1.414 2001/07/30 19:59:05 ad Exp
 #
 #	GENERIC_LAPTOP -- GENERIC with cardbus and some USB devices enabled
@@ -8,7 +8,7 @@
 
 #options 	INCLUDE_CONFIG_FILE	# embed config file in kernel binary
 
-#ident 		"GENERIC-$Revision: 1.170 $"
+#ident 		"GENERIC-$Revision: 1.171 $"
 
 maxusers	32		# estimated number of users
 
@@ -33,6 +33,9 @@
 options 	MTRR		# memory-type range register syscall support
 #options 	PERFCTRS	# performance-monitoring counters support
 
+options 	MULTIBOOT	# Multiboot support (see multiboot(8))
+#options 	MULTIBOOT_SYMTAB_SPACE=1048576
+
 # delay between "rebooting ..." message and hardware reset, in milliseconds
 #options 	CPURESET_DELAY=2000
 
--- a/sys/arch/i386/conf/files.i386	Fri Feb 03 11:04:46 2006 +0000
+++ b/sys/arch/i386/conf/files.i386	Fri Feb 03 11:08:23 2006 +0000
@@ -1,4 +1,4 @@
-#	$NetBSD: files.i386,v 1.276 2006/01/01 12:12:43 xtraeme Exp $
+#	$NetBSD: files.i386,v 1.277 2006/02/03 11:08:23 jmmv Exp $
 #
 # new style config file for i386 architecture
 #
@@ -64,6 +64,11 @@
 # Enhanced SpeedStep
 defflag			ENHANCED_SPEEDSTEP
 
+# Multiboot support
+defflag opt_multiboot.h		MULTIBOOT
+defparam opt_multiboot.h	MULTIBOOT_SYMTAB_SPACE
+file	arch/i386/i386/multiboot.c	multiboot
+
 # PowerNow K7
 defflag			POWERNOW_K7
 
--- a/sys/arch/i386/i386/locore.S	Fri Feb 03 11:04:46 2006 +0000
+++ b/sys/arch/i386/i386/locore.S	Fri Feb 03 11:08:23 2006 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: locore.S,v 1.36 2005/12/11 12:17:41 christos Exp $	*/
+/*	$NetBSD: locore.S,v 1.37 2006/02/03 11:08:24 jmmv Exp $	*/
 
 /*-
  * Copyright (c) 1998, 2000, 2004 The NetBSD Foundation, Inc.
@@ -101,6 +101,8 @@
 #include <machine/i82489reg.h>
 #endif
 
+#include <machine/multiboot.h>
+
 /* LINTSTUB: include <sys/types.h> */
 /* LINTSTUB: include <machine/cpu.h> */
 /* LINTSTUB: include <sys/systm.h> */
@@ -224,6 +226,40 @@
 	.globl	start
 start:	movw	$0x1234,0x472			# warm boot
 
+#if defined(MULTIBOOT)
+	jmp	1f
+
+	.align	4
+	.globl	Multiboot_Header
+_C_LABEL(Multiboot_Header):
+#define MULTIBOOT_HEADER_FLAGS	(MULTIBOOT_HEADER_WANT_MEMORY | \
+				 MULTIBOOT_HEADER_HAS_ADDR)
+	.long	MULTIBOOT_HEADER_MAGIC
+	.long	MULTIBOOT_HEADER_FLAGS
+	.long	-(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS)
+	.long	RELOC(Multiboot_Header)
+	.long	RELOC(start)
+	.long	RELOC(_edata)
+	.long	RELOC(_end) + MULTIBOOT_SYMTAB_SPACE
+	.long	RELOC(start)
+
+1:
+	/* Check if we are being executed by a Multiboot-compliant boot
+	 * loader. */
+	cmpl	$MULTIBOOT_INFO_MAGIC,%eax
+	jne	1f
+
+	/* Indeed, a multiboot-compliat boot loader executed us.  We copy
+	 * the received Multiboot information structure into kernel's data
+	 * space to process it later -- after we are relocated.  It will
+	 * be safer to run complex C code than doing it at this point. */
+	pushl	%ebx		# Address of Multiboot information
+	call	_C_LABEL(multiboot_pre_reloc)
+	addl	$4,%esp
+	jmp	3f
+#endif
+
+1:
 	/*
 	 * Load parameters from stack
 	 * (howto, [bootdev], bootinfo, esym, basemem, extmem).
@@ -284,6 +320,7 @@
 	movl	%eax,RELOC(biosbasemem)
 1:
 
+3:
 	/* First, reset the PSL. */
 	pushl	$PSL_MBO
 	popfl
@@ -633,6 +670,14 @@
 	movl	%esi,PCB_CR3(%eax)	# pcb->pcb_cr3
 	xorl	%ebp,%ebp               # mark end of frames
 
+#if defined(MULTIBOOT)
+	/* It is now safe to parse the Multiboot information structure
+	 * we saved before from C code.  Note that we cannot delay its
+	 * parsing any more because initgdt (called below) needs to make
+	 * use of this information. */
+	call	_C_LABEL(multiboot_post_reloc)
+#endif
+
 	subl	$NGDT*8, %esp		# space for temporary gdt
 	pushl	%esp
 	call	_C_LABEL(initgdt)
--- a/sys/arch/i386/i386/machdep.c	Fri Feb 03 11:04:46 2006 +0000
+++ b/sys/arch/i386/i386/machdep.c	Fri Feb 03 11:08:23 2006 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: machdep.c,v 1.569 2005/12/30 13:37:57 jmmv Exp $	*/
+/*	$NetBSD: machdep.c,v 1.570 2006/02/03 11:08:24 jmmv Exp $	*/
 
 /*-
  * Copyright (c) 1996, 1997, 1998, 2000, 2004 The NetBSD Foundation, Inc.
@@ -72,7 +72,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.569 2005/12/30 13:37:57 jmmv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.570 2006/02/03 11:08:24 jmmv Exp $");
 
 #include "opt_beep.h"
 #include "opt_compat_ibcs2.h"
@@ -143,6 +143,7 @@
 #include <machine/specialreg.h>
 #include <machine/bootinfo.h>
 #include <machine/mtrr.h>
+#include <machine/multiboot.h>
 
 #include <dev/isa/isareg.h>
 #include <machine/isa_machdep.h>
@@ -303,6 +304,10 @@
 
 	printf("%s%s", copyright, version);
 
+#ifdef MULTIBOOT
+	multiboot_print_info();
+#endif
+
 #ifdef TRAPLOG
 	/*
 	 * Enable recording of branch from/to in MSR's
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/arch/i386/i386/multiboot.c	Fri Feb 03 11:08:23 2006 +0000
@@ -0,0 +1,717 @@
+/*	$NetBSD: multiboot.c,v 1.1 2006/02/03 11:08:24 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.1 2006/02/03 11:08:24 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 <machine/bootinfo.h>
+#include <machine/multiboot.h>
+
+#if !defined(MULTIBOOT)
+#  error "MULTIBOOT not defined; this cannot happen."
+#endif
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * External variables.  All of them, with the exception of 'end', must
+ * be set at some point within this file.
+ */
+extern int		biosbasemem;
+extern int		biosextmem;
+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];
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * Simplified ELF image that contains the symbol table for the booted
+ * kernel.  Stuck after the kernel image (in memory).
+ *
+ * Must be less than MULTIBOOT_SYMTAB_SPACE in bytes.  Otherwise, there
+ * is no guarantee that it will not overwrite other stuff passed in by
+ * the boot loader.
+ */
+struct symbols_image {
+	Elf32_Ehdr	i_ehdr;
+	Elf32_Shdr	i_shdr[4];
+	char		i_strtab[32];
+	char		i_data; /* Actually longer. */
+};
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * 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 *);
+static void	setup_syms(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);
+	setup_syms(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;
+
+	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 && esym == 0)
+		printf("multiboot: Symbol table too big; try increasing "
+		    "MULTIBOOT_SYMTAB_SPACE\n");
+}
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * 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 symbols_image *si;
+
+	/*
+	 * Check if the Multiboot information header has symbols or not.
+	 */
+	if (!(mi->mi_flags & MULTIBOOT_INFO_HAS_ELF_SYMS))
+		return;
+
+	/*
+	 * 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;
+
+	/*
+	 * Check if the symbol table will fit after the kernel image.
+	 * If not, ignore it; there is nothing else we can do (except
+	 * maybe copying only part of the table... but that could be
+	 * as useless as not copying it).
+	 */
+	if (sizeof(si) + symtabp->sh_size + strtabp->sh_size >
+	    MULTIBOOT_SYMTAB_SPACE)
+		return;
+
+	/*
+	 * Prepare space after the kernel to create a simple ELF image
+	 * that holds the symbol table and the string table previously
+	 * found.
+	 *
+	 * This goes just after the BSS section to let the bootstraping
+	 * code relocate it (up to esym's value).
+	 */
+	memset(RELOC(char *, &end), 0, MULTIBOOT_SYMTAB_SPACE);
+	si = RELOC(struct symbols_image *, &end);
+
+	/*
+	 * Create a minimal ELF header (as required by ksyms_init).
+	 */
+	memcpy(si->i_ehdr.e_ident, ELFMAG, SELFMAG);
+	si->i_ehdr.e_ident[EI_CLASS] = ELFCLASS32;
+	si->i_ehdr.e_type = ET_EXEC;
+	si->i_ehdr.e_version = 1;
+	si->i_ehdr.e_shoff = offsetof(struct symbols_image, i_shdr);
+	si->i_ehdr.e_ehsize = sizeof(si->i_ehdr);
+	si->i_ehdr.e_shentsize = sizeof(si->i_shdr[0]);
+	si->i_ehdr.e_shnum = 2;
+	si->i_ehdr.e_shstrndx = SHN_UNDEF;
+
+	/*
+	 * First section: default empty entry; cleared by the previous
+	 * memset.  Explicitly set fields that use symbolic values.
+	 */
+	si->i_shdr[0].sh_type = SHT_NULL;
+	si->i_shdr[0].sh_link = SHN_UNDEF;
+
+	/*
+	 * Second section: the symbol table.
+	 */
+	memcpy(&si->i_shdr[1], symtabp, sizeof(si->i_shdr[1]));
+	si->i_shdr[1].sh_name = 1;
+	si->i_shdr[1].sh_addr = (vaddr_t)(&end) +
+	    offsetof(struct symbols_image, i_shdr[1]);
+	si->i_shdr[1].sh_offset = offsetof(struct symbols_image, i_data);
+	si->i_shdr[1].sh_link = 2;
+
+	memcpy(RELOC(uint8_t *, (vaddr_t)(&end)) + si->i_shdr[1].sh_offset,
+	    (void *)symtabp->sh_addr, symtabp->sh_size);
+
+	/*
+	 * Third section: the strings table.
+	 */
+	memcpy(&si->i_shdr[2], strtabp, sizeof(si->i_shdr[2]));
+	si->i_shdr[1].sh_name = 9;
+	si->i_shdr[2].sh_addr = (vaddr_t)(&end) +
+	    offsetof(struct symbols_image, i_shdr[2]);
+	si->i_shdr[2].sh_offset = offsetof(struct symbols_image, i_data) +
+	    si->i_shdr[1].sh_size;
+	si->i_shdr[2].sh_link = SHN_UNDEF;
+
+	memcpy(RELOC(uint8_t *, (vaddr_t)(&end)) + si->i_shdr[2].sh_offset,
+	    (void *)strtabp->sh_addr, strtabp->sh_size);
+
+	/*
+	 * Fourth section: the section header strings table used by this
+	 * minimal ELF image.
+	 */
+	si->i_shdr[3].sh_name = 17;
+	si->i_shdr[3].sh_type = SHT_STRTAB;
+	si->i_shdr[3].sh_offset = offsetof(struct symbols_image, i_strtab);
+	si->i_shdr[3].sh_size = sizeof(si->i_strtab);
+	si->i_shdr[3].sh_addralign = 1;
+	si->i_shdr[3].sh_link = SHN_UNDEF;
+
+	strcpy(&si->i_strtab[1], ".symtab");
+	strcpy(&si->i_strtab[9], ".strtab");
+	strcpy(&si->i_strtab[17], ".shstrtab");
+
+	/*
+	 * Set up the 'esym' global variable to point to the end of the
+	 * minimal ELF image (end of symbols).
+	 */
+	*RELOC(int *, &esym) = ((vaddr_t)&end) + si->i_shdr[2].sh_offset +
+	    si->i_shdr[2].sh_size;
+#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;
+
+		/* XXX: This should use x86_alldisks to find the correct
+		 * match.  But, at this point, neither the drivers nor the
+		 * vector are initialized... */
+		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 = "";
+		}
+
+		if (devprefix[0] != '\0') {
+			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;
+
+	biosbasemem = mi->mi_mem_lower;
+	biosextmem = mi->mi_mem_upper;
+}
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * Sets up the symtab bootinfo structure to describe where the symbols
+ * are if copy_syms() found them.
+ */
+static void
+setup_syms(struct multiboot_info *mi)
+{
+	struct btinfo_symtab bi;
+	struct symbols_image *si;
+
+	if (esym == 0)
+		return;
+
+	si = (struct symbols_image *)(&end);
+
+	bi.ssym = (int)(&end) - KERNBASE;
+	bi.esym = (int)esym - KERNBASE;
+	bi.nsym = si->i_shdr[1].sh_size / sizeof(Elf32_Sym);
+
+	bootinfo_add((struct btinfo_common *)&bi, BTINFO_SYMTAB,
+	    sizeof(struct btinfo_symtab));
+}
--- a/sys/arch/i386/include/Makefile	Fri Feb 03 11:04:46 2006 +0000
+++ b/sys/arch/i386/include/Makefile	Fri Feb 03 11:08:23 2006 +0000
@@ -1,4 +1,4 @@
-#	$NetBSD: Makefile,v 1.29 2005/12/11 12:17:43 christos Exp $
+#	$NetBSD: Makefile,v 1.30 2006/02/03 11:08:24 jmmv Exp $
 
 INCSDIR= /usr/include/i386
 
@@ -15,7 +15,7 @@
 	joystick.h \
 	kcore.h \
 	limits.h lock.h \
-	math.h mcontext.h mtrr.h \
+	math.h mcontext.h mtrr.h multiboot.h \
 	npx.h \
 	param.h pcb.h pccons.h pio.h pmap.h pmc.h proc.h profile.h psl.h \
 	pte.h ptrace.h \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/arch/i386/include/multiboot.h	Fri Feb 03 11:08:23 2006 +0000
@@ -0,0 +1,218 @@
+/*	$NetBSD: multiboot.h,v 1.1 2006/02/03 11:08:24 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.
+ */
+
+#if defined(_KERNEL)
+
+#include "opt_multiboot.h"
+
+#if defined(MULTIBOOT)
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * Space reserved after the kernel image to stick the symbol table.
+ * The boot loader will leave this memory untouched (it will be treated
+ * as if it was part of the BSS section).
+ */
+#if !defined(MULTIBOOT_SYMTAB_SPACE)
+#  define MULTIBOOT_SYMTAB_SPACE 1048576
+#endif
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * Multiboot header structure.
+ */
+#define MULTIBOOT_HEADER_MAGIC		0x1BADB002
+#define MULTIBOOT_HEADER_MODS_ALIGNED	0x00000001
+#define MULTIBOOT_HEADER_WANT_MEMORY	0x00000002
+#define MULTIBOOT_HEADER_HAS_VBE	0x00000004
+#define MULTIBOOT_HEADER_HAS_ADDR	0x00010000
+
+#if !defined(_LOCORE)
+struct multiboot_header {
+	uint32_t	mh_magic;
+	uint32_t	mh_flags;
+	uint32_t	mh_checksum;
+
+	/* Valid if mh_flags sets MULTIBOOT_HEADER_HAS_ADDR. */
+	paddr_t		mh_header_addr;
+	paddr_t		mh_load_addr;
+	paddr_t		mh_load_end_addr;
+	paddr_t		mh_bss_end_addr;
+	paddr_t		mh_entry_addr;
+
+	/* Valid if mh_flags sets MULTIBOOT_HEADER_HAS_VBE. */
+	uint32_t	mh_mode_type;
+	uint32_t	mh_width;
+	uint32_t	mh_height;
+	uint32_t	mh_depth;
+};
+#endif /* !defined(_LOCORE) */
+
+/*
+ * Symbols defined in locore.S.
+ */
+#if !defined(_LOCORE)
+extern struct multiboot_header *Multiboot_Header;
+#endif /* !defined(_LOCORE) */
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * Multiboot information structure.
+ */
+#define MULTIBOOT_INFO_MAGIC		0x2BADB002
+#define MULTIBOOT_INFO_HAS_MEMORY	0x00000001
+#define MULTIBOOT_INFO_HAS_BOOT_DEVICE	0x00000002
+#define MULTIBOOT_INFO_HAS_CMDLINE	0x00000004
+#define MULTIBOOT_INFO_HAS_MODS		0x00000008
+#define MULTIBOOT_INFO_HAS_AOUT_SYMS	0x00000010
+#define MULTIBOOT_INFO_HAS_ELF_SYMS	0x00000020
+#define MULTIBOOT_INFO_HAS_MMAP		0x00000040
+#define MULTIBOOT_INFO_HAS_DRIVES	0x00000080
+#define MULTIBOOT_INFO_HAS_CONFIG_TABLE	0x00000100
+#define MULTIBOOT_INFO_HAS_LOADER_NAME	0x00000200
+#define MULTIBOOT_INFO_HAS_APM_TABLE	0x00000400
+#define MULTIBOOT_INFO_HAS_VBE		0x00000800
+
+#if !defined(_LOCORE)
+struct multiboot_info {
+	uint32_t	mi_flags;
+
+	/* Valid if mi_flags sets MULTIBOOT_INFO_HAS_MEMORY. */
+	uint32_t	mi_mem_lower;
+	uint32_t	mi_mem_upper;
+
+	/* Valid if mi_flags sets MULTIBOOT_INFO_HAS_BOOT_DEVICE. */
+	uint8_t		mi_boot_device_part3;
+	uint8_t		mi_boot_device_part2;
+	uint8_t		mi_boot_device_part1;
+	uint8_t		mi_boot_device_drive;
+
+	/* Valid if mi_flags sets MULTIBOOT_INFO_HAS_CMDLINE. */
+	char *		mi_cmdline;
+
+	/* Valid if mi_flags sets MULTIBOOT_INFO_HAS_MODS. */
+	uint32_t	unused_mi_mods_count;
+	vaddr_t		unused_mi_mods_addr;
+
+	/* Valid if mi_flags sets MULTIBOOT_INFO_HAS_{AOUT,ELF}_SYMS. */
+	uint32_t	mi_elfshdr_num;
+	uint32_t	mi_elfshdr_size;
+	vaddr_t		mi_elfshdr_addr;
+	uint32_t	mi_elfshdr_shndx;
+
+	/* Valid if mi_flags sets MULTIBOOT_INFO_HAS_MMAP. */
+	uint32_t	mi_mmap_length;
+	vaddr_t		mi_mmap_addr;
+
+	/* Valid if mi_flags sets MULTIBOOT_INFO_HAS_DRIVES. */
+	uint32_t	mi_drives_length;
+	vaddr_t		mi_drives_addr;
+
+	/* Valid if mi_flags sets MULTIBOOT_INFO_HAS_CONFIG_TABLE. */
+	void *		unused_mi_config_table;
+
+	/* Valid if mi_flags sets MULTIBOOT_INFO_HAS_LOADER_NAME. */
+	char *		mi_loader_name;
+
+	/* Valid if mi_flags sets MULTIBOOT_INFO_HAS_APM. */
+	void *		unused_mi_apm_table;
+
+	/* Valid if mi_flags sets MULTIBOOT_INFO_HAS_VBE. */
+	void *		unused_mi_vbe_control_info;
+	void *		unused_mi_vbe_mode_info;
+	paddr_t		unused_mi_vbe_interface_seg;
+	paddr_t		unused_mi_vbe_interface_off;
+	uint32_t	unused_mi_vbe_interface_len;
+};
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * Drive information.  This describes an entry in the drives table as
+ * pointed to by mi_drives_addr.
+ */
+struct multiboot_drive {
+	uint32_t	md_length;
+	uint8_t		md_number;
+	uint8_t		md_mode;
+	uint16_t	md_cylinders;
+	uint8_t		md_heads;
+	uint8_t		md_sectors;
+
+	/* The variable-sized 'ports' field comes here, so this structure
+	 * can be longer. */
+};
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * Memory mapping.  This describes an entry in the memory mappings table
+ * as pointed to by mi_mmap_addr.
+ *
+ * Be aware that mm_size specifies the size of all other fields *except*
+ * for mm_size.  In order to jump between two different entries, you
+ * have to count mm_size + 4 bytes.
+ */
+struct multiboot_mmap {
+	uint32_t	mm_size;
+	uint64_t	mm_base_addr;
+	uint64_t	mm_length;
+	uint32_t	mm_type;
+};
+
+#endif /* !defined(_LOCORE) */
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * Prototypes for public functions defined in multiboot.c.
+ */
+#if !defined(_LOCORE)
+void		multiboot_pre_reloc(struct multiboot_info *);
+void		multiboot_post_reloc(void);
+void		multiboot_print_info(void);
+#endif /* !defined(_LOCORE) */
+
+/* --------------------------------------------------------------------- */
+
+#endif /* defined(MULTIBOOT) */
+
+#endif /* defined(_KERNEL) */
--- a/sys/arch/x86/include/bootinfo.h	Fri Feb 03 11:04:46 2006 +0000
+++ b/sys/arch/x86/include/bootinfo.h	Fri Feb 03 11:08:23 2006 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: bootinfo.h,v 1.10 2005/12/30 13:37:57 jmmv Exp $	*/
+/*	$NetBSD: bootinfo.h,v 1.11 2006/02/03 11:08:24 jmmv Exp $	*/
 
 /*
  * Copyright (c) 1997
@@ -34,6 +34,7 @@
 };
 
 #define BTINFO_BOOTPATH		0
+#define BTINFO_ROOTDEVICE	1
 #define BTINFO_BOOTDISK		3
 #define BTINFO_NETIF		4
 #define BTINFO_CONSOLE		6
@@ -47,6 +48,11 @@
 	char bootpath[80];
 };
 
+struct btinfo_rootdevice {
+	struct btinfo_common common;
+	char devname[16];
+};
+
 struct btinfo_bootdisk {
 	struct btinfo_common common;
 	int labelsector; /* label valid if != -1 */
--- a/sys/arch/x86/x86/consinit.c	Fri Feb 03 11:04:46 2006 +0000
+++ b/sys/arch/x86/x86/consinit.c	Fri Feb 03 11:08:23 2006 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: consinit.c,v 1.8 2005/12/11 12:19:47 christos Exp $	*/
+/*	$NetBSD: consinit.c,v 1.9 2006/02/03 11:08:24 jmmv Exp $	*/
 
 /*
  * Copyright (c) 1998
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: consinit.c,v 1.8 2005/12/11 12:19:47 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: consinit.c,v 1.9 2006/02/03 11:08:24 jmmv Exp $");
 
 #include "opt_kgdb.h"
 
@@ -195,8 +195,15 @@
 #if (NCOM > 0)
 	if (!strcmp(consinfo->devname, "com")) {
 		bus_space_tag_t tag = X86_BUS_SPACE_IO;
+		int addr = consinfo->addr;
+		int speed = consinfo->speed;
 
-		if (comcnattach(tag, consinfo->addr, consinfo->speed,
+		if (addr == 0)
+			addr = CONADDR;
+		if (speed == 0)
+			speed = CONSPEED;
+
+		if (comcnattach(tag, addr, speed,
 				COM_FREQ, COM_TYPE_NORMAL, comcnmode))
 			panic("can't init serial console @%x", consinfo->addr);
 
--- a/sys/arch/x86/x86/x86_autoconf.c	Fri Feb 03 11:04:46 2006 +0000
+++ b/sys/arch/x86/x86/x86_autoconf.c	Fri Feb 03 11:08:23 2006 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: x86_autoconf.c,v 1.5 2005/12/11 12:19:47 christos Exp $	*/
+/*	$NetBSD: x86_autoconf.c,v 1.6 2006/02/03 11:08:24 jmmv Exp $	*/
 
 /*-
  * Copyright (c) 1990 The Regents of the University of California.
@@ -364,6 +364,7 @@
 static void
 findroot(void)
 {
+	struct btinfo_rootdevice *biv;
 	struct btinfo_bootdisk *bid;
 	struct btinfo_bootwedge *biw;
 	struct device *dv;
@@ -387,6 +388,27 @@
 		return;
 	}
 
+	if ((biv = lookup_bootinfo(BTINFO_ROOTDEVICE)) != NULL) {
+		for (dv = TAILQ_FIRST(&alldevs); dv != NULL;
+		     dv = TAILQ_NEXT(dv, dv_list)) {
+			struct cfdata *cd;
+			size_t len;
+
+			if (dv->dv_class != DV_DISK)
+				continue;
+
+			cd = dv->dv_cfdata;
+			len = strlen(cd->cf_name);
+
+			if (strncmp(cd->cf_name, biv->devname, len) == 0 &&
+			    biv->devname[len] - '0' == cd->cf_unit) {
+				booted_device = dv;
+				booted_partition = biv->devname[len + 1] - 'a';
+				return;
+			}
+		}
+	}
+
 	if ((biw = lookup_bootinfo(BTINFO_BOOTWEDGE)) != NULL) {
 		/*
 		 * Scan all disk devices for ones that match the passed data.