Index: loader/i386/multiboot.c =================================================================== --- loader/i386/multiboot.c (revision 2023) +++ loader/i386/multiboot.c (working copy) @@ -42,16 +42,60 @@ #include #include #include #include #include +static grub_err_t +grub_multiboot_unload (void); + +static inline void * +grub_multiboot_relocated (void *orig) +{ + return (((char *) orig) - grub_multiboot_payload_orig + + grub_multiboot_payload_dest); +} + extern grub_dl_t my_mod; static struct grub_multiboot_info *mbi, *mbi_dest; -static grub_addr_t entry; +struct grub_mod_list *modlist = 0; static char *playground = NULL; +/* Allocate space from multiboot_payload aligned at ALIGN*/ +static char * +grub_multiboot_memalign (grub_size_t align, grub_size_t size) +{ + grub_size_t align_overhead; + grub_off_t mbioff = (char *)mbi - playground; + char *ret; + align_overhead = align - (grub_multiboot_payload_dest + + grub_multiboot_payload_size) % align; + if (align_overhead == align) + align_overhead = 0; + + playground = grub_realloc (playground, RELOCATOR_SIZEOF (forward) + + grub_multiboot_payload_size + align_overhead + + size); + if (!playground) + { + grub_multiboot_unload (); + return 0; + } + + grub_multiboot_payload_orig + = (grub_uint32_t) (playground + RELOCATOR_SIZEOF (forward)); + mbi = (struct grub_multiboot_info *) (playground + mbioff); + ret = playground + RELOCATOR_SIZEOF (forward) + + grub_multiboot_payload_size + align_overhead; + grub_multiboot_payload_size += align_overhead + size; + return ret; +} + static grub_err_t grub_multiboot_boot (void) { + struct grub_mod_list *modlist2; + grub_addr_t entry; + char *back_dest; + grub_stop_floppy (); + /* Dirty hack VSTa overwrites the page following last module so put module + index further */ + grub_multiboot_memalign (1, 1048576); + + modlist2 = (struct grub_mod_list *) + grub_multiboot_memalign (1, mbi->mods_count + * sizeof (struct grub_mod_list)); + if (!modlist2) + return grub_error (GRUB_ERR_OUT_OF_MEMORY, + "couldn't allocate space for module index"); + grub_memcpy (modlist2, modlist, mbi->mods_count + * sizeof (struct grub_mod_list)); + mbi->mods_addr = (grub_uint32_t) grub_multiboot_relocated (modlist2); + + back_dest = grub_multiboot_memalign (1, RELOCATOR_SIZEOF(backward)); + + if (grub_multiboot_payload_dest >= grub_multiboot_payload_orig) + { + grub_memmove (playground, &grub_multiboot_forward_relocator, + RELOCATOR_SIZEOF(forward)); + entry = (grub_addr_t) playground; + } + else + { + grub_memmove (back_dest, &grub_multiboot_backward_relocator, + RELOCATOR_SIZEOF(backward)); + grub_multiboot_payload_size -= RELOCATOR_SIZEOF(backward); + entry = (grub_addr_t) grub_multiboot_payload_orig + + grub_multiboot_payload_size; + } + grub_multiboot_real_boot (entry, mbi_dest); /* Not reached. */ @@ -61,21 +140,11 @@ grub_multiboot_boot (void) static grub_err_t grub_multiboot_unload (void) { - if (mbi) - { - unsigned int i; - for (i = 0; i < mbi->mods_count; i++) - { - grub_free ((void *) - ((struct grub_mod_list *) mbi->mods_addr)[i].mod_start); - grub_free ((void *) - ((struct grub_mod_list *) mbi->mods_addr)[i].cmdline); - } - grub_free ((void *) mbi->mods_addr); - grub_free ((void *) mbi->cmdline); - grub_free (mbi); - } - + grub_free (playground); + grub_free (modlist); + + playground = 0; + modlist = 0; mbi = 0; grub_dl_unref (my_mod); @@ -283,7 +352,9 @@ grub_multiboot (int argc, char *argv[]) grub_multiboot_payload_size += load_size; grub_multiboot_payload_dest = header->load_addr; - playground = grub_malloc (RELOCATOR_SIZEOF(forward) + grub_multiboot_payload_size + RELOCATOR_SIZEOF(backward)); + playground = grub_malloc (RELOCATOR_SIZEOF(forward) + + grub_multiboot_payload_size + + RELOCATOR_SIZEOF(backward)); if (! playground) goto fail; @@ -318,19 +389,7 @@ grub_multiboot (int argc, char *argv[]) mbi->mmap_addr = mmap_addr (grub_multiboot_payload_dest); mbi->flags |= MULTIBOOT_INFO_MEM_MAP; - if (grub_multiboot_payload_dest >= grub_multiboot_payload_orig) - { - grub_memmove (playground, &grub_multiboot_forward_relocator, RELOCATOR_SIZEOF(forward)); - entry = (grub_addr_t) playground; - } - else - { - grub_memmove ((char *) (grub_multiboot_payload_orig + grub_multiboot_payload_size), - &grub_multiboot_backward_relocator, RELOCATOR_SIZEOF(backward)); - entry = (grub_addr_t) grub_multiboot_payload_orig + grub_multiboot_payload_size; - } - - grub_dprintf ("multiboot_loader", "dest=%p, size=0x%x, entry_offset=0x%x\n", + grub_dprintf ("multiboot_loader", "mbi_dest=%p, dest=%p, size=0x%x, entry_offset=0x%x\n", mbi_dest, (void *) grub_multiboot_payload_dest, grub_multiboot_payload_size, grub_multiboot_payload_entry_offset); @@ -385,6 +444,7 @@ grub_module (int argc, char *argv[]) grub_file_t file = 0; grub_ssize_t size, len = 0; char *module = 0, *cmdline = 0, *p; + grub_uint32_t moduledest, cmdlinedest; int i; if (argc == 0) @@ -400,27 +460,13 @@ grub_module (int argc, char *argv[]) goto fail; } - file = grub_gzfile_open (argv[0], 1); - if (! file) - goto fail; - - size = grub_file_size (file); - module = grub_memalign (MULTIBOOT_MOD_ALIGN, size); - if (! module) - goto fail; - - if (grub_file_read (file, module, size) != size) - { - grub_error (GRUB_ERR_FILE_READ_ERROR, "Couldn't read file"); - goto fail; - } - for (i = 0; i < argc; i++) len += grub_strlen (argv[i]) + 1; - cmdline = p = grub_malloc (len); + cmdline = p = grub_multiboot_memalign (1, len); if (! cmdline) goto fail; + cmdlinedest = (grub_uint32_t) grub_multiboot_relocated (cmdline); for (i = 0; i < argc; i++) { @@ -431,33 +477,46 @@ grub_module (int argc, char *argv[]) /* Remove the space after the last word. */ *(--p) = '\0'; + file = grub_gzfile_open (argv[0], 1); + if (! file) + goto fail; + + /* Specification doesn't require modules to be page-aligned however grub1 + does it and we want maximal compatibility */ + size = grub_file_size (file); + module = grub_multiboot_memalign (MULTIBOOT_MOD_ALIGN, size); + if (! module) + goto fail; + moduledest = (grub_uint32_t) grub_multiboot_relocated (module); + + if (grub_file_read (file, module, size) != size) + { + grub_error (GRUB_ERR_FILE_READ_ERROR, "Couldn't read file"); + goto fail; + } + if (mbi->flags & MULTIBOOT_INFO_MODS) { - struct grub_mod_list *modlist = (struct grub_mod_list *) mbi->mods_addr; - modlist = grub_realloc (modlist, (mbi->mods_count + 1) * sizeof (struct grub_mod_list)); if (! modlist) goto fail; - mbi->mods_addr = (grub_uint32_t) modlist; - modlist += mbi->mods_count; - modlist->mod_start = (grub_uint32_t) module; - modlist->mod_end = (grub_uint32_t) module + size; - modlist->cmdline = (grub_uint32_t) cmdline; - modlist->pad = 0; + modlist[mbi->mods_count].mod_start = moduledest; + modlist[mbi->mods_count].mod_end = moduledest + size; + modlist[mbi->mods_count].cmdline = cmdlinedest; + modlist[mbi->mods_count].pad = 0; mbi->mods_count++; } else { - struct grub_mod_list *modlist = grub_malloc (sizeof (struct grub_mod_list)); + modlist = grub_malloc (sizeof (struct grub_mod_list)); if (! modlist) goto fail; - modlist->mod_start = (grub_uint32_t) module; - modlist->mod_end = (grub_uint32_t) module + size; - modlist->cmdline = (grub_uint32_t) cmdline; + modlist->mod_start = moduledest; + modlist->mod_end = moduledest + size; + modlist->cmdline = cmdlinedest; modlist->pad = 0; mbi->mods_count = 1; - mbi->mods_addr = (grub_uint32_t) modlist; mbi->flags |= MULTIBOOT_INFO_MODS; } @@ -465,9 +524,4 @@ grub_module (int argc, char *argv[]) if (file) grub_file_close (file); - if (grub_errno != GRUB_ERR_NONE) - { - grub_free (module); - grub_free (cmdline); - } } Index: ChangeLog =================================================================== --- ChangeLog (revision 2023) +++ ChangeLog (working copy) @@ -1,3 +1,14 @@ +2009-03-10 Vladimir Serbinenko + + Put multiboot modules directly after the kernel + + * loader/i386/multiboot.c (grub_multiboot_relocated): new function + (grub_multiboot_memalign): likewise + (grub_multiboot_boot): finalise multiboot index and copy relocator + (grub_multiboot_unload): don't free pointers in playground + (grub_multiboot): defer copying relocator + (grub_module): use new allocator functions + 2009-03-09 Felix Zielcke * conf/powerpc-ieee1275.rmk (grub_emu_SOURCES): Remove duplicated