summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Brown2007-01-12 13:03:19 +0100
committerMichael Brown2007-01-12 13:03:19 +0100
commit0f29e0e46e1ccdc7000805ca0ea38e603f248462 (patch)
treedca1c70ae17055c3fa0132f3ec1991619e85dfef
parentFix the memory map. (diff)
downloadipxe-0f29e0e46e1ccdc7000805ca0ea38e603f248462.tar.gz
ipxe-0f29e0e46e1ccdc7000805ca0ea38e603f248462.tar.xz
ipxe-0f29e0e46e1ccdc7000805ca0ea38e603f248462.zip
Ensure multiboot modules are in ascending order of memory start
address, to work around OS bugs.
-rw-r--r--src/arch/i386/image/multiboot.c55
1 files changed, 40 insertions, 15 deletions
diff --git a/src/arch/i386/image/multiboot.c b/src/arch/i386/image/multiboot.c
index 2411aec43..25f5d2b07 100644
--- a/src/arch/i386/image/multiboot.c
+++ b/src/arch/i386/image/multiboot.c
@@ -106,28 +106,53 @@ multiboot_build_module_list ( struct image *image,
struct image *module_image;
struct multiboot_module *module;
unsigned int count = 0;
+ unsigned int insert;
+ physaddr_t start;
+ physaddr_t end;
+ unsigned int i;
+ /* Add each image as a multiboot module */
for_each_image ( module_image ) {
/* Do not include kernel image itself as a module */
if ( module_image == image )
continue;
- module = &modules[count++];
- /* Populate module data structure, if applicable */
- if ( ! modules )
- continue;
- module->mod_start = user_to_phys ( module_image->data, 0 );
- module->mod_end = user_to_phys ( module_image->data,
- module_image->len );
- module->string = virt_to_phys ( module_image->cmdline );
- module->reserved = 0;
- DBG ( "Multiboot module %lx is [%lx,%lx)\n",
- virt_to_phys ( module ),
- module->mod_start, module->mod_end );
-
- /* We promise to page-align modules, so at least check */
- assert ( ( module->mod_start & 0xfff ) == 0 );
+ /* If we don't have a data structure to populate, just count */
+ if ( modules ) {
+
+ /* At least some OSes expect the multiboot
+ * modules to be in ascending order, so we
+ * have to support it.
+ */
+ start = user_to_phys ( module_image->data, 0 );
+ end = user_to_phys ( module_image->data,
+ module_image->len );
+ for ( insert = 0 ; insert < count ; insert++ ) {
+ if ( start < modules[insert].mod_start )
+ break;
+ }
+ module = &modules[insert];
+ memmove ( ( module + 1 ), module,
+ ( ( count - insert ) * sizeof ( *module ) ));
+ module->mod_start = start;
+ module->mod_end = end;
+ module->string = virt_to_phys ( module_image->cmdline);
+ module->reserved = 0;
+
+ /* We promise to page-align modules */
+ assert ( ( module->mod_start & 0xfff ) == 0 );
+ }
+
+ count++;
+ }
+
+ /* Dump module configuration */
+ if ( modules ) {
+ for ( i = 0 ; i < count ; i++ ) {
+ DBG ( "Multiboot module %d is [%lx,%lx)\n", i,
+ modules[i].mod_start, modules[i].mod_end );
+ }
}
return count;