loader/multiboot: fix multiboot loading

The current multiboot loader code doesn't clean the metadata added to the
kernel after the bi_load64 dry run, which breaks accounting of the required
memory for the metadata.

This issue didn't show itself before because all the metadata items where small
(8bytes), but after r316343 there's a big blob in the metadata, which triggers
this. Fix it by cleaning the metadata added to the kernel after the bi_load64
dry run. Also add a comment describing the memory layout when booting using
multiboot (Xen Dom0).

This unbreaks booting a FreeBSD/Xen Dom0 after r316343.

MFC after:	3 weeks
Sponsored by:	Citrix Systems R&D
This commit is contained in:
Roger Pau Monné 2017-04-13 09:59:12 +00:00
parent 9f67a48145
commit 6696a07ed5
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=316754
3 changed files with 59 additions and 0 deletions

View File

@ -228,6 +228,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

View File

@ -663,6 +663,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)
{

View File

@ -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.