NetBSD Problem Report #42640

From gregoire.sutre@labri.fr  Mon Jan 18 20:25:59 2010
Return-Path: <gregoire.sutre@labri.fr>
Received: from mail.netbsd.org (mail.netbsd.org [204.152.190.11])
	by www.NetBSD.org (Postfix) with ESMTP id 8464C63BA2A
	for <gnats-bugs@gnats.NetBSD.org>; Mon, 18 Jan 2010 20:25:59 +0000 (UTC)
Message-Id: <20100118202547.8BDFA1238A@niagara.localdomain>
Date: Mon, 18 Jan 2010 21:25:47 +0100 (CET)
From: gregoire.sutre@gmail.com
Reply-To: gregoire.sutre@gmail.com
To: gnats-bugs@gnats.NetBSD.org
Subject: Kernel module support for multiboot
X-Send-Pr-Version: 3.95

>Number:         42640
>Category:       port-i386
>Synopsis:       Kernel multiboot implementation lacks support for modules
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    port-i386-maintainer
>State:          open
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Mon Jan 18 20:30:00 +0000 2010
>Originator:     gregoire.sutre@gmail.com
>Release:        NetBSD 5.0_STABLE
>Organization:
>Environment:
System: NetBSD niagara 5.0_STABLE NetBSD 5.0_STABLE (NIAGARA) #0: Sat Oct 24 11:54:39 CEST 2009 instsoft@niagara:/usr/build/usr/src/sys/arch/i386/compile/NIAGARA i386
Architecture: i386
Machine: i386
>Description:
The kernel (i386) implementation of the multiboot specification lacks
support for kernel modules.  A patch adding module support is provided
below.  The patch transforms the multiboot module information into
bootinfo module information, as is already done for the rest of the
multiboot implementation.

The patch has been tested successfully with a development version of
GRUB 2.  When booting with NetBSD's native boot-loader (by multiboot),
the pre-loaded modules are recognized but linking fails with an error
message ``symbol not found''.  This is likely due to the fact that the
native boot loader's multiboot implementation does not provide the
kernel symbol table.  However, the boot process continues without any
additional problem.

>How-To-Repeat:
>Fix:
--- multiboot.c.netbsd-5	2008-10-11 13:06:19.000000000 +0200
+++ multiboot.c	2010-01-18 19:37:12.000000000 +0100
@@ -50,6 +50,13 @@ __KERNEL_RCSID(0, "$NetBSD: multiboot.c,
 #  error "MULTIBOOT not defined; this cannot happen."
 #endif

+/*
+ * Constants for the declaration of static variables (MBI relocation).
+ * XXX Transform MB_MOD_MAX into a kernel option?
+ */
+#define MB_MOD_MAX	10	/* Maximum number of modules */
+#define MB_MOD_STRLEN	80	/* Length of module strings */
+
 /* --------------------------------------------------------------------- */

 /*
@@ -78,6 +85,7 @@ extern int		boothowto;
 extern struct bootinfo	bootinfo;
 extern int		end;
 extern int *		esym;
+extern int *		eblob;

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

@@ -94,7 +102,9 @@ static struct multiboot_info	Multiboot_I
 static bool			Multiboot_Loader = false;
 static char			Multiboot_Loader_Name[255];
 static uint8_t			Multiboot_Mmap[1024];
+static struct multiboot_module	Multiboot_Modules[MB_MOD_MAX];
 static struct multiboot_symbols	Multiboot_Symbols;
+static char			Mmo_Strings[MB_MOD_MAX][MB_MOD_STRLEN];

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

@@ -103,6 +113,7 @@ static struct multiboot_symbols	Multiboo
  */
 static void	bootinfo_add(struct btinfo_common *, int, int);
 static void	copy_syms(struct multiboot_info *);
+static uint32_t	multiboot_pre_reloc_modules(struct multiboot_info *);
 static void	setup_biosgeom(struct multiboot_info *);
 static void	setup_bootdisk(struct multiboot_info *);
 static void	setup_bootpath(struct multiboot_info *);
@@ -110,6 +121,7 @@ static void	setup_console(struct multibo
 static void	setup_howto(struct multiboot_info *);
 static void	setup_memory(struct multiboot_info *);
 static void	setup_memmap(struct multiboot_info *);
+static void	setup_modules(struct multiboot_info *);

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

@@ -151,17 +163,24 @@ multiboot_pre_reloc(struct multiboot_inf
 	}

 	if (mi->mi_flags & MULTIBOOT_INFO_HAS_MMAP) {
+		/* XXX Are we sure that mi->mi_mmap_length <= 1024 ? */
 		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) {
+		/* XXX Are we sure that mi->mi_drives_length <= 255 ? */
 		memcpy(RELOC(void *, Multiboot_Drives),
 		    (void *)mi->mi_drives_addr, mi->mi_drives_length);
 		midest->mi_drives_addr = (vaddr_t)&Multiboot_Drives;
 	}

+	if (mi->mi_flags & MULTIBOOT_INFO_HAS_MODS) {
+		midest->mi_mods_count = multiboot_pre_reloc_modules(mi);
+		midest->mi_mods_addr = (vaddr_t)&Multiboot_Modules;
+	}
+
 	copy_syms(mi);
 #undef RELOC
 }
@@ -169,6 +188,57 @@ multiboot_pre_reloc(struct multiboot_inf
 /* --------------------------------------------------------------------- */

 /*
+ * Helper function for multiboot_pre_reloc.
+ */
+uint32_t
+multiboot_pre_reloc_modules(struct multiboot_info *mi)
+{
+#define RELOC(type, x) ((type)((vaddr_t)(x) - KERNBASE))
+	struct multiboot_module *mbm;
+	uint32_t max_mmo_end;
+	uint32_t truncated_mi_mods_count;
+	int i;
+
+	/*
+	 * Limit the number of modules to MB_MOD_MAX.
+	 * XXX Record the real number of modules to display a warning?
+	 */
+	truncated_mi_mods_count = mi->mi_mods_count;
+	if (truncated_mi_mods_count > MB_MOD_MAX)
+		truncated_mi_mods_count = MB_MOD_MAX;
+
+	memcpy(RELOC(void *, Multiboot_Modules),
+	    (void *)mi->mi_mods_addr,
+	    truncated_mi_mods_count * sizeof(struct multiboot_module));
+
+	/* max_mmo_end shall contain the maximum end_address of modules. */
+	max_mmo_end = 0;
+
+	mbm = (struct multiboot_module *)mi->mi_mods_addr;
+	for (i = 0; i < truncated_mi_mods_count; i++) {
+		strncpy(RELOC(char *, Mmo_Strings[i]),
+		    mbm->mmo_string, MB_MOD_STRLEN);
+		*RELOC(char *, &(Mmo_Strings[i][MB_MOD_STRLEN-1])) = '\0';
+		*RELOC(char **, &(Multiboot_Modules[i].mmo_string)) =
+		    Mmo_Strings[i];
+		if (mbm->mmo_end > max_mmo_end)
+			max_mmo_end = mbm->mmo_end;
+		mbm++;
+	}
+	/*
+	 * Record into eblob where loaded modules end, as we must skip over
+	 * them. See occurrences of eblob in locore.S and machdep.c.
+	 */
+	if (max_mmo_end)
+		*RELOC(int **, &eblob) = (int *)(max_mmo_end + KERNBASE);
+
+	return truncated_mi_mods_count;
+#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
@@ -192,6 +262,7 @@ multiboot_post_reloc(void)
 	setup_biosgeom(mi);
 	setup_bootdisk(mi);
 	setup_memmap(mi);
+	setup_modules(mi);
 }

 /* --------------------------------------------------------------------- */
@@ -230,6 +301,20 @@ multiboot_print_info(void)
 		printf("multiboot: String table at %p, length %d bytes\n",
 		    ms->s_strstart, ms->s_strsize);
 	}
+
+	if (mi->mi_flags & MULTIBOOT_INFO_HAS_MODS) {
+		struct multiboot_module *mbm;
+		int i;
+
+		mbm = (struct multiboot_module *)mi->mi_mods_addr;
+		for (i = 0; i < mi->mi_mods_count; i++) {
+			printf("multiboot: module %d: %s, "
+			    "starts at %p, ends at %p\n",
+			    i, mbm->mmo_string,
+			    (void *)mbm->mmo_start, (void *)mbm->mmo_end);
+			mbm++;
+		}
+	}
 }

 /* --------------------------------------------------------------------- */
@@ -711,3 +796,47 @@ multiboot_ksyms_init(void)

 	return mi->mi_flags & MULTIBOOT_INFO_HAS_ELF_SYMS;
 }
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * Sets up the modulelist bootinfo structure if the Multiboot information
+ * structure provides information about modules.
+ */
+static void
+setup_modules(struct multiboot_info *mi)
+{
+	uint8_t bidata[sizeof(struct btinfo_modulelist) +
+	    (MB_MOD_MAX * sizeof(struct bi_modulelist_entry))];
+	struct multiboot_module *mbm;
+	struct btinfo_modulelist *biml;
+	struct bi_modulelist_entry *bime;
+	int i;
+
+	if (!(mi->mi_flags & MULTIBOOT_INFO_HAS_MODS))
+		return;
+
+	if (!(mi->mi_mods_count))
+		return;
+
+	memset(bidata, 0, sizeof(bidata));
+	biml = (struct btinfo_modulelist *)bidata;
+	biml->num = mi->mi_mods_count;
+	biml->endpa = 0; /* only used to set eblob in native boot */
+
+	bime = (struct bi_modulelist_entry *)(biml + 1);
+	mbm = (struct multiboot_module *)mi->mi_mods_addr;
+	for (i = 0; i < mi->mi_mods_count; i++) {
+		strncpy(bime->path, mbm->mmo_string, sizeof(bime->path));
+		bime->path[sizeof(bime->path) - 1] = '\0';
+		bime->type = BI_MODULE_ELF;
+		bime->base = mbm->mmo_start;
+		bime->len = mbm->mmo_end - mbm->mmo_start;
+		bime++;
+		mbm++;
+	}
+
+	bootinfo_add((struct btinfo_common *)biml, BTINFO_MODULELIST,
+	    sizeof(struct btinfo_modulelist) +
+	    (biml->num * sizeof(struct bi_modulelist_entry)));
+}

NetBSD Home
NetBSD PR Database Search

(Contact us) $NetBSD: query-full-pr,v 1.39 2013/11/01 18:47:49 spz Exp $
$NetBSD: gnats_config.sh,v 1.8 2006/05/07 09:23:38 tsutsui Exp $
Copyright © 1994-2007 The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.