summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorroyger <royger@FreeBSD.org>2017-05-09 09:53:18 +0000
committerroyger <royger@FreeBSD.org>2017-05-09 09:53:18 +0000
commitf20a7aeef0f6912c9d47d5ceb488ff7b745c5369 (patch)
treec81475e713b208d6570fe587744b6141305847c8
parente776c54686e61cb89b170e3ec621f197edd73050 (diff)
downloadFreeBSD-src-f20a7aeef0f6912c9d47d5ceb488ff7b745c5369.zip
FreeBSD-src-f20a7aeef0f6912c9d47d5ceb488ff7b745c5369.tar.gz
MFC r316754: loader/multiboot: fix multiboot loading
Sponsored by: Citrix Systems R&D
-rw-r--r--sys/boot/common/bootstrap.h1
-rw-r--r--sys/boot/common/module.c16
-rw-r--r--sys/boot/i386/libi386/multiboot.c42
3 files changed, 59 insertions, 0 deletions
diff --git a/sys/boot/common/bootstrap.h b/sys/boot/common/bootstrap.h
index 472fc3e..a4c8939 100644
--- a/sys/boot/common/bootstrap.h
+++ b/sys/boot/common/bootstrap.h
@@ -229,6 +229,7 @@ void file_discard(struct preloaded_file *fp);
void file_addmetadata(struct preloaded_file *fp, int type, size_t size, void *p);
int file_addmodule(struct preloaded_file *fp, char *modname, int version,
struct kernel_module **newmp);
+void file_removemetadata(struct preloaded_file *fp);
/* MI module loaders */
#ifdef __elfN
diff --git a/sys/boot/common/module.c b/sys/boot/common/module.c
index 15c4807..e96aabb 100644
--- a/sys/boot/common/module.c
+++ b/sys/boot/common/module.c
@@ -642,6 +642,22 @@ file_findmetadata(struct preloaded_file *fp, int type)
return(md);
}
+/*
+ * Remove all metadata from the file.
+ */
+void
+file_removemetadata(struct preloaded_file *fp)
+{
+ struct file_metadata *md, *next;
+
+ for (md = fp->f_metadata; md != NULL; md = next)
+ {
+ next = md->md_next;
+ free(md);
+ }
+ fp->f_metadata = NULL;
+}
+
struct file_metadata *
metadata_next(struct file_metadata *md, int type)
{
diff --git a/sys/boot/i386/libi386/multiboot.c b/sys/boot/i386/libi386/multiboot.c
index 00e36f2..9aac640 100644
--- a/sys/boot/i386/libi386/multiboot.c
+++ b/sys/boot/i386/libi386/multiboot.c
@@ -267,7 +267,39 @@ multiboot_exec(struct preloaded_file *fp)
* information is placed at the start of the second module and
* the original modulep value is saved together with the other
* metadata, so we can relocate everything.
+ *
+ * Native layout:
+ * fp->f_addr + fp->f_size
+ * +---------+----------------+------------+
+ * | | | |
+ * | Kernel | Modules | Metadata |
+ * | | | |
+ * +---------+----------------+------------+
+ * fp->f_addr modulep kernend
+ *
+ * Xen layout:
+ *
+ * Initial:
+ * fp->f_addr + fp->f_size
+ * +---------+----------+----------------+------------+
+ * | | | | |
+ * | Kernel | Reserved | Modules | Metadata |
+ * | | | | dry run |
+ * +---------+----------+----------------+------------+
+ * fp->f_addr
+ *
+ * After metadata polacement (ie: final):
+ * fp->f_addr + fp->f_size
+ * +-----------+---------+----------+----------------+
+ * | | | | |
+ * | Kernel | Free | Metadata | Modules |
+ * | | | | |
+ * +-----------+---------+----------+----------------+
+ * fp->f_addr modulep kernend
+ * \__________/ \__________________________/
+ * Multiboot module 0 Multiboot module 1
*/
+
fp = file_findfile(NULL, "elf kernel");
if (fp == NULL) {
printf("No FreeBSD kernel provided, aborting\n");
@@ -275,6 +307,13 @@ multiboot_exec(struct preloaded_file *fp)
goto error;
}
+ if (fp->f_metadata != NULL) {
+ printf("FreeBSD kernel already contains metadata, aborting\n");
+ error = EINVAL;
+ goto error;
+ }
+
+
mb_mod = malloc(sizeof(struct multiboot_mod_list) * NUM_MODULES);
if (mb_mod == NULL) {
error = ENOMEM;
@@ -312,6 +351,9 @@ multiboot_exec(struct preloaded_file *fp)
goto error;
}
+ /* Clean the metadata added to the kernel in the bi_load64 dry run */
+ file_removemetadata(fp);
+
/*
* This is the position where the second multiboot module
* will be placed.
OpenPOWER on IntegriCloud