NetBSD-Bugs archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
port-i386/42640: Kernel module support for multiboot
>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@localhost
>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)));
+}
Home |
Main Index |
Thread Index |
Old Index