From cd0514794a7948f5166c26cf7383f430e6a04b6a Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sun, 10 Jan 2010 18:58:18 +0100 Subject: [PATCH 1/2] MAnipulate mbi in abstract way --- ChangeLog.abstractmbi | 25 +++ conf/i386-coreboot.rmk | 6 +- conf/i386-pc.rmk | 4 +- include/grub/multiboot.h | 13 ++ loader/i386/multiboot.c | 320 +++++++------------------------- loader/i386/multiboot_elfxx.c | 5 +- loader/i386/multiboot_mbi.c | 336 ++++++++++++++++++++++++++++++++++ 7 files changed, 453 insertions(+), 256 deletions(-) create mode 100644 ChangeLog.abstractmbi create mode 100644 loader/i386/multiboot_mbi.c diff --git a/ChangeLog.abstractmbi b/ChangeLog.abstractmbi new file mode 100644 index 000000000..a5ff55b08 --- /dev/null +++ b/ChangeLog.abstractmbi @@ -0,0 +1,25 @@ +2010-01-10 Vladimir Serbinenko + + * conf/i386-coreboot.rmk (multiboot_mod_SOURCES): + Add loader/i386/multiboot_mbi.c. + (multiboot2_mod_SOURCES): Likewise. + * conf/i386-pc.rmk (multiboot_mod_SOURCES): Likewise. + (multiboot2_mod_SOURCES): Likewise. + * include/grub/multiboot.h (grub_multiboot_get_mbi_size): New proto. + (grub_multiboot_make_mbi): Likewise. + (grub_multiboot_free_mbi): Likewise. + (grub_multiboot_init_mbi): Likewise. + (grub_multiboot_add_module): Likewise. + (grub_multiboot_set_bootdev): Likewise. + * loader/i386/multiboot.c (mbi): Removed. + (mbi_dest): Likewise. + (alloc_mbi): New variable. + (grub_multiboot_payload_size): Removed. All users updated. + (grub_multiboot_pure_size): New variable. + (grub_multiboot_boot): Use grub_multiboot_make_mbi. + (grub_multiboot_unload): Use grub_multiboot_free_mbi. + (grub_get_multiboot_mmap_len): Moved to loader/i386/multiboot_mbi.c. + (grub_fill_multiboot_mmap): Likewise. + (grub_multiboot_get_bootdev): Likewise. + (grub_multiboot): Use multiboot_mbi functions. + * loader/i386/multiboot_mbi.c: New file. diff --git a/conf/i386-coreboot.rmk b/conf/i386-coreboot.rmk index 95ee79436..d73c9f0e2 100644 --- a/conf/i386-coreboot.rmk +++ b/conf/i386-coreboot.rmk @@ -142,14 +142,16 @@ serial_mod_LDFLAGS = $(COMMON_LDFLAGS) pkglib_MODULES += multiboot.mod multiboot_mod_SOURCES = loader/i386/multiboot.c \ - loader/multiboot_loader.c + loader/i386/multiboot_mbi.c \ + loader/multiboot_loader.c multiboot_mod_CFLAGS = $(COMMON_CFLAGS) multiboot_mod_LDFLAGS = $(COMMON_LDFLAGS) multiboot_mod_ASFLAGS = $(COMMON_ASFLAGS) pkglib_MODULES += multiboot2.mod multiboot2_mod_SOURCES = loader/i386/multiboot.c \ - loader/multiboot_loader.c + loader/multiboot_loader.c \ + loader/i386/multiboot_mbi.c multiboot2_mod_CFLAGS = $(COMMON_CFLAGS) -DGRUB_USE_MULTIBOOT2 multiboot2_mod_LDFLAGS = $(COMMON_LDFLAGS) multiboot2_mod_ASFLAGS = $(COMMON_ASFLAGS) diff --git a/conf/i386-pc.rmk b/conf/i386-pc.rmk index 4215f0a34..2a69571aa 100644 --- a/conf/i386-pc.rmk +++ b/conf/i386-pc.rmk @@ -203,6 +203,7 @@ serial_mod_LDFLAGS = $(COMMON_LDFLAGS) pkglib_MODULES += multiboot.mod multiboot_mod_SOURCES = loader/i386/multiboot.c \ + loader/i386/multiboot_mbi.c \ loader/multiboot_loader.c multiboot_mod_CFLAGS = $(COMMON_CFLAGS) multiboot_mod_LDFLAGS = $(COMMON_LDFLAGS) @@ -210,7 +211,8 @@ multiboot_mod_ASFLAGS = $(COMMON_ASFLAGS) pkglib_MODULES += multiboot2.mod multiboot2_mod_SOURCES = loader/i386/multiboot.c \ - loader/multiboot_loader.c + loader/i386/multiboot_mbi.c \ + loader/multiboot_loader.c multiboot2_mod_CFLAGS = $(COMMON_CFLAGS) -DGRUB_USE_MULTIBOOT2 multiboot2_mod_LDFLAGS = $(COMMON_LDFLAGS) multiboot2_mod_ASFLAGS = $(COMMON_ASFLAGS) diff --git a/include/grub/multiboot.h b/include/grub/multiboot.h index 041ee1f18..f9edb0c59 100644 --- a/include/grub/multiboot.h +++ b/include/grub/multiboot.h @@ -29,7 +29,20 @@ #include #endif +#include +#include + void grub_multiboot (int argc, char *argv[]); void grub_module (int argc, char *argv[]); +grub_size_t grub_multiboot_get_mbi_size (void); +grub_err_t grub_multiboot_make_mbi (void *orig, grub_uint32_t dest, + grub_off_t buf_off, grub_size_t bufsize); +void grub_multiboot_free_mbi (void); +grub_err_t grub_multiboot_init_mbi (int argc, char *argv[]); +grub_err_t grub_multiboot_add_module (grub_addr_t start, grub_size_t size, + int argc, char *argv[]); +void grub_multiboot_set_bootdev (void); + + #endif /* ! GRUB_MULTIBOOT_HEADER */ diff --git a/loader/i386/multiboot.c b/loader/i386/multiboot.c index f4869594e..2a69327b4 100644 --- a/loader/i386/multiboot.c +++ b/loader/i386/multiboot.c @@ -45,31 +45,24 @@ #include #include #include -#ifdef GRUB_MACHINE_PCBIOS -#include -#include -#include -#include -#endif #include extern grub_dl_t my_mod; -static struct multiboot_info *mbi, *mbi_dest; - -static grub_size_t code_size; +static grub_size_t code_size, alloc_mbi; char *grub_multiboot_payload_orig; grub_addr_t grub_multiboot_payload_dest; -grub_size_t grub_multiboot_payload_size; +grub_size_t grub_multiboot_pure_size; grub_uint32_t grub_multiboot_payload_eip; static grub_err_t grub_multiboot_boot (void) { + grub_size_t mbi_size; + grub_err_t err; struct grub_relocator32_state state = { .eax = MULTIBOOT_BOOTLOADER_MAGIC, - .ebx = PTR_TO_UINT32 (mbi_dest), .ecx = 0, .edx = 0, .eip = grub_multiboot_payload_eip, @@ -78,6 +71,24 @@ grub_multiboot_boot (void) .esp = 0x7ff00 }; + mbi_size = grub_multiboot_get_mbi_size (); + if (alloc_mbi < mbi_size) + { + grub_multiboot_payload_orig + = grub_relocator32_realloc (grub_multiboot_payload_orig, + grub_multiboot_pure_size + mbi_size); + if (!grub_multiboot_payload_orig) + return grub_errno; + alloc_mbi = mbi_size; + } + + state.ebx = grub_multiboot_payload_dest + grub_multiboot_pure_size; + err = grub_multiboot_make_mbi (grub_multiboot_payload_orig, + grub_multiboot_payload_dest, + grub_multiboot_pure_size, mbi_size); + if (err) + return err; + grub_relocator32_boot (grub_multiboot_payload_orig, grub_multiboot_payload_dest, state); @@ -89,69 +100,18 @@ 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 multiboot_mod_list *) mbi->mods_addr)[i].mod_start); - grub_free ((void *) - ((struct multiboot_mod_list *) mbi->mods_addr)[i].cmdline); - } - grub_free ((void *) mbi->mods_addr); - } + grub_multiboot_free_mbi (); + grub_relocator32_free (grub_multiboot_payload_orig); - mbi = NULL; + alloc_mbi = 0; + grub_multiboot_payload_orig = NULL; grub_dl_unref (my_mod); return GRUB_ERR_NONE; } -/* Return the length of the Multiboot mmap that will be needed to allocate - our platform's map. */ -static grub_uint32_t -grub_get_multiboot_mmap_len (void) -{ - grub_size_t count = 0; - - auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t); - int NESTED_FUNC_ATTR hook (grub_uint64_t addr __attribute__ ((unused)), - grub_uint64_t size __attribute__ ((unused)), - grub_uint32_t type __attribute__ ((unused))) - { - count++; - return 0; - } - - grub_mmap_iterate (hook); - - return count * sizeof (struct multiboot_mmap_entry); -} - -/* Fill previously allocated Multiboot mmap. */ -static void -grub_fill_multiboot_mmap (struct multiboot_mmap_entry *first_entry) -{ - struct multiboot_mmap_entry *mmap_entry = (struct multiboot_mmap_entry *) first_entry; - - auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t); - int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size, grub_uint32_t type) - { - mmap_entry->addr = addr; - mmap_entry->len = size; - mmap_entry->type = type; - mmap_entry->size = sizeof (struct multiboot_mmap_entry) - sizeof (mmap_entry->size); - mmap_entry++; - - return 0; - } - - grub_mmap_iterate (hook); -} - #define MULTIBOOT_LOAD_ELF64 #include "multiboot_elfxx.c" #undef MULTIBOOT_LOAD_ELF64 @@ -172,58 +132,13 @@ grub_multiboot_load_elf (grub_file_t file, void *buffer) return grub_error (GRUB_ERR_UNKNOWN_OS, "unknown ELF class"); } -static int -grub_multiboot_get_bootdev (grub_uint32_t *bootdev) -{ -#ifdef GRUB_MACHINE_PCBIOS - char *p; - grub_uint32_t biosdev, slice = ~0, part = ~0; - grub_device_t dev; - - biosdev = grub_get_root_biosnumber (); - - dev = grub_device_open (0); - if (dev && dev->disk && dev->disk->partition) - { - - p = dev->disk->partition->partmap->get_name (dev->disk->partition); - if (p) - { - if ((p[0] >= '0') && (p[0] <= '9')) - { - slice = grub_strtoul (p, &p, 0) - 1; - - if ((p) && (p[0] == ',')) - p++; - } - - if ((p[0] >= 'a') && (p[0] <= 'z')) - part = p[0] - 'a'; - } - } - if (dev) - grub_device_close (dev); - - *bootdev = ((biosdev & 0xff) << 24) | ((slice & 0xff) << 16) - | ((part & 0xff) << 8) | 0xff; - return (biosdev != ~0UL); -#else - *bootdev = 0xffffffff; - return 0; -#endif -} - void grub_multiboot (int argc, char *argv[]) { grub_file_t file = 0; - char buffer[MULTIBOOT_SEARCH], *cmdline = 0, *p; + char buffer[MULTIBOOT_SEARCH]; struct multiboot_header *header; - grub_ssize_t len, cmdline_length, boot_loader_name_length; - grub_uint32_t mmap_length; - int i; - int cmdline_argc; - char **cmdline_argv; + grub_ssize_t len; grub_loader_unset (); @@ -274,31 +189,8 @@ grub_multiboot (int argc, char *argv[]) grub_relocator32_free (grub_multiboot_payload_orig); grub_multiboot_payload_orig = NULL; - mmap_length = grub_get_multiboot_mmap_len (); - - /* Figure out cmdline length. */ /* Skip filename. */ - cmdline_argc = argc - 1; - cmdline_argv = argv + 1; - - for (i = 0, cmdline_length = 0; i < cmdline_argc; i++) - cmdline_length += grub_strlen (cmdline_argv[i]) + 1; - - if (cmdline_length == 0) - cmdline_length = 1; - - boot_loader_name_length = sizeof(PACKAGE_STRING); - -#define cmdline_addr(x) ((void *) ((x) + code_size)) -#define boot_loader_name_addr(x) \ - ((void *) ((x) + code_size + cmdline_length)) -#define mbi_addr(x) ((void *) ((x) + code_size + cmdline_length + boot_loader_name_length)) -#define mmap_addr(x) ((void *) ((x) + code_size + cmdline_length + boot_loader_name_length + sizeof (struct multiboot_info))) - - grub_multiboot_payload_size = cmdline_length - /* boot_loader_name_length might need to grow for mbi,etc to be aligned (see below) */ - + boot_loader_name_length + 3 - + sizeof (struct multiboot_info) + mmap_length; + grub_multiboot_init_mbi (argc - 1, argv + 1); if (header->flags & MULTIBOOT_AOUT_KLUDGE) { @@ -313,10 +205,12 @@ grub_multiboot (int argc, char *argv[]) code_size = load_size; grub_multiboot_payload_dest = header->load_addr; - grub_multiboot_payload_size += code_size; + grub_multiboot_pure_size += code_size; + /* Allocate a bit more to avoid relocations in most cases. */ + alloc_mbi = grub_multiboot_get_mbi_size () + 65536; grub_multiboot_payload_orig - = grub_relocator32_alloc (grub_multiboot_payload_size); + = grub_relocator32_alloc (grub_multiboot_pure_size + alloc_mbi); if (! grub_multiboot_payload_orig) goto fail; @@ -338,53 +232,35 @@ grub_multiboot (int argc, char *argv[]) else if (grub_multiboot_load_elf (file, buffer) != GRUB_ERR_NONE) goto fail; - /* This provides alignment for the MBI, the memory map and the backward relocator. */ - boot_loader_name_length += (0x04 - ((unsigned long) mbi_addr (grub_multiboot_payload_dest) & 0x03)); - - mbi = mbi_addr (grub_multiboot_payload_orig); - mbi_dest = mbi_addr (grub_multiboot_payload_dest); - grub_memset (mbi, 0, sizeof (struct multiboot_info)); - mbi->mmap_length = mmap_length; - - grub_fill_multiboot_mmap (mmap_addr (grub_multiboot_payload_orig)); - - /* FIXME: grub_uint32_t will break for addresses above 4 GiB, but is mandated - by the spec. Is there something we can do about it? */ - mbi->mmap_addr = (grub_uint32_t) mmap_addr (grub_multiboot_payload_dest); - mbi->flags |= MULTIBOOT_INFO_MEM_MAP; - - /* Convert from bytes to kilobytes. */ - mbi->mem_lower = grub_mmap_get_lower () / 1024; - mbi->mem_upper = grub_mmap_get_upper () / 1024; - mbi->flags |= MULTIBOOT_INFO_MEMORY; - - cmdline = p = cmdline_addr (grub_multiboot_payload_orig); - if (! cmdline) - goto fail; - - for (i = 0; i < cmdline_argc; i++) + if (header->flags & MULTIBOOT_VIDEO_MODE) { - p = grub_stpcpy (p, cmdline_argv[i]); - *(p++) = ' '; + switch (header->mode_type) + { + case 1: + grub_env_set ("gfxpayload", "text"); + break; + + case 0: + { + char buf[sizeof ("XXXXXXXXXXxXXXXXXXXXXxXXXXXXXXXX,XXXXXXXXXXxXXXXXXXXXX,auto")]; + if (header->depth && header->width && header->height) + grub_sprintf (buf, "%dx%dx%d,%dx%d,auto", header->width, + header->height, header->depth, header->width, + header->height); + else if (header->width && header->height) + grub_sprintf (buf, "%dx%d,auto", header->width, header->height); + else + grub_sprintf (buf, "auto"); + + grub_env_set ("gfxpayload", buf); + break; + } + } } - /* Remove the space after the last word. */ - if (p != cmdline) - p--; - *p = 0; + grub_multiboot_set_bootdev (); - mbi->flags |= MULTIBOOT_INFO_CMDLINE; - mbi->cmdline = (grub_uint32_t) cmdline_addr (grub_multiboot_payload_dest); - - - grub_strcpy (boot_loader_name_addr (grub_multiboot_payload_orig), PACKAGE_STRING); - mbi->flags |= MULTIBOOT_INFO_BOOT_LOADER_NAME; - mbi->boot_loader_name = (grub_uint32_t) boot_loader_name_addr (grub_multiboot_payload_dest); - - if (grub_multiboot_get_bootdev (&mbi->boot_device)) - mbi->flags |= MULTIBOOT_INFO_BOOTDEV; - - grub_loader_set (grub_multiboot_boot, grub_multiboot_unload, 1); + grub_loader_set (grub_multiboot_boot, grub_multiboot_unload, 0); fail: if (file) @@ -392,22 +268,18 @@ grub_multiboot (int argc, char *argv[]) if (grub_errno != GRUB_ERR_NONE) { - grub_free (cmdline); - grub_free (mbi); + grub_relocator32_free (grub_multiboot_payload_orig); grub_dl_unref (my_mod); } } - void grub_module (int argc, char *argv[]) { grub_file_t file = 0; - grub_ssize_t size, len = 0; - char *module = 0, *cmdline = 0, *p; - int i; - int cmdline_argc; - char **cmdline_argv; + grub_ssize_t size; + char *module = 0; + grub_err_t err; if (argc == 0) { @@ -415,7 +287,7 @@ grub_module (int argc, char *argv[]) goto fail; } - if (!mbi) + if (!grub_multiboot_payload_orig) { grub_error (GRUB_ERR_BAD_ARGUMENT, "you need to load the multiboot kernel first"); @@ -431,73 +303,19 @@ grub_module (int argc, char *argv[]) if (! module) goto fail; + err = grub_multiboot_add_module ((grub_addr_t) module, size, + argc - 1, argv + 1); + if (err) + goto fail; + if (grub_file_read (file, module, size) != size) { grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file"); goto fail; } - /* Skip module name. */ - cmdline_argc = argc - 1; - cmdline_argv = argv + 1; - - for (i = 0; i < cmdline_argc; i++) - len += grub_strlen (cmdline_argv[i]) + 1; - - if (len == 0) - len = 1; - - cmdline = p = grub_malloc (len); - if (! cmdline) - goto fail; - - for (i = 0; i < cmdline_argc; i++) - { - p = grub_stpcpy (p, cmdline_argv[i]); - *(p++) = ' '; - } - - /* Remove the space after the last word. */ - if (p != cmdline) - p--; - *p = '\0'; - - if (mbi->flags & MULTIBOOT_INFO_MODS) - { - struct multiboot_mod_list *modlist = (struct multiboot_mod_list *) mbi->mods_addr; - - modlist = grub_realloc (modlist, (mbi->mods_count + 1) - * sizeof (struct multiboot_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; - mbi->mods_count++; - } - else - { - struct multiboot_mod_list *modlist = grub_zalloc (sizeof (struct multiboot_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; - mbi->mods_count = 1; - mbi->mods_addr = (grub_uint32_t) modlist; - mbi->flags |= MULTIBOOT_INFO_MODS; - } - fail: if (file) grub_file_close (file); - - if (grub_errno != GRUB_ERR_NONE) - { - grub_free (module); - grub_free (cmdline); - } } + diff --git a/loader/i386/multiboot_elfxx.c b/loader/i386/multiboot_elfxx.c index 80db25144..8f6367432 100644 --- a/loader/i386/multiboot_elfxx.c +++ b/loader/i386/multiboot_elfxx.c @@ -100,10 +100,11 @@ CONCAT(grub_multiboot_load_elf, XX) (grub_file_t file, void *buffer) code_size = (phdr(highest_segment)->p_paddr + phdr(highest_segment)->p_memsz) - phdr(lowest_segment)->p_paddr; grub_multiboot_payload_dest = phdr(lowest_segment)->p_paddr; - grub_multiboot_payload_size += code_size; + grub_multiboot_pure_size += code_size; + alloc_mbi = grub_multiboot_get_mbi_size (); grub_multiboot_payload_orig - = grub_relocator32_alloc (grub_multiboot_payload_size); + = grub_relocator32_alloc (grub_multiboot_pure_size + alloc_mbi); if (!grub_multiboot_payload_orig) return grub_errno; diff --git a/loader/i386/multiboot_mbi.c b/loader/i386/multiboot_mbi.c new file mode 100644 index 000000000..58802d44c --- /dev/null +++ b/loader/i386/multiboot_mbi.c @@ -0,0 +1,336 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2007,2008,2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#ifdef GRUB_MACHINE_PCBIOS +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +struct module +{ + struct module *next; + grub_addr_t start; + grub_size_t size; + char *cmdline; + int cmdline_size; +}; + +struct module *modules, *modules_last; +static grub_size_t cmdline_size; +static grub_size_t total_modcmd; +static unsigned modcnt; +static char *cmdline = NULL; +static grub_uint32_t bootdev; +static int bootdev_set; + +/* Return the length of the Multiboot mmap that will be needed to allocate + our platform's map. */ +static grub_uint32_t +grub_get_multiboot_mmap_len (void) +{ + grub_size_t count = 0; + + auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t); + int NESTED_FUNC_ATTR hook (grub_uint64_t addr __attribute__ ((unused)), + grub_uint64_t size __attribute__ ((unused)), + grub_uint32_t type __attribute__ ((unused))) + { + count++; + return 0; + } + + grub_mmap_iterate (hook); + + return count * sizeof (struct multiboot_mmap_entry); +} + +grub_size_t +grub_multiboot_get_mbi_size (void) +{ + return sizeof (struct multiboot_info) + ALIGN_UP (cmdline_size, 4) + + modcnt * sizeof (struct multiboot_mod_list) + total_modcmd + + ALIGN_UP (sizeof(PACKAGE_STRING), 4) + grub_get_multiboot_mmap_len (); +} + +/* Fill previously allocated Multiboot mmap. */ +static void +grub_fill_multiboot_mmap (struct multiboot_mmap_entry *first_entry) +{ + struct multiboot_mmap_entry *mmap_entry = (struct multiboot_mmap_entry *) first_entry; + + auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t); + int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size, grub_uint32_t type) + { + mmap_entry->addr = addr; + mmap_entry->len = size; + switch (type) + { + case GRUB_MACHINE_MEMORY_AVAILABLE: + mmap_entry->type = MULTIBOOT_MEMORY_AVAILABLE; + break; + + default: + mmap_entry->type = MULTIBOOT_MEMORY_RESERVED; + break; + } + mmap_entry->size = sizeof (struct multiboot_mmap_entry) - sizeof (mmap_entry->size); + mmap_entry++; + + return 0; + } + + grub_mmap_iterate (hook); +} + +grub_err_t +grub_multiboot_make_mbi (void *orig, grub_uint32_t dest, grub_off_t buf_off, + grub_size_t bufsize) +{ + grub_uint8_t *ptrorig = (grub_uint8_t *) orig + buf_off; + grub_uint32_t ptrdest = dest + buf_off; + struct multiboot_info *mbi; + struct multiboot_mod_list *modlist; + unsigned i; + struct module *cur; + grub_size_t mmap_size; + + if (bufsize < grub_multiboot_get_mbi_size ()) + return grub_error (GRUB_ERR_OUT_OF_MEMORY, "mbi buffer is too small"); + + mbi = (struct multiboot_info *) ptrorig; + ptrorig += sizeof (*mbi); + ptrdest += sizeof (*mbi); + grub_memset (mbi, 0, sizeof (*mbi)); + + grub_memcpy (ptrorig, cmdline, cmdline_size); + mbi->flags |= MULTIBOOT_INFO_CMDLINE; + mbi->cmdline = ptrdest; + ptrorig += ALIGN_UP (cmdline_size, 4); + ptrdest += ALIGN_UP (cmdline_size, 4); + + grub_memcpy (ptrorig, PACKAGE_STRING, sizeof(PACKAGE_STRING)); + mbi->flags |= MULTIBOOT_INFO_BOOT_LOADER_NAME; + mbi->boot_loader_name = ptrdest; + ptrorig += ALIGN_UP (sizeof(PACKAGE_STRING), 4); + ptrdest += ALIGN_UP (sizeof(PACKAGE_STRING), 4); + + if (modcnt) + { + mbi->flags |= MULTIBOOT_INFO_MODS; + mbi->mods_addr = ptrdest; + mbi->mods_count = modcnt; + modlist = (struct multiboot_mod_list *) ptrorig; + ptrorig += modcnt * sizeof (struct multiboot_mod_list); + ptrdest += modcnt * sizeof (struct multiboot_mod_list); + + for (i = 0, cur = modules; i < modcnt; i++, cur = cur->next) + { + modlist[i].mod_start = cur->start; + modlist[i].mod_end = modlist[i].mod_start + cur->size; + modlist[i].cmdline = ptrdest; + grub_memcpy (ptrorig, cur->cmdline, cur->cmdline_size); + ptrorig += ALIGN_UP (cur->cmdline_size, 4); + ptrdest += ALIGN_UP (cur->cmdline_size, 4); + } + } + else + { + mbi->mods_addr = 0; + mbi->mods_count = 0; + } + + mmap_size = grub_get_multiboot_mmap_len (); + grub_fill_multiboot_mmap ((struct multiboot_mmap_entry *) ptrorig); + mbi->mmap_length = mmap_size; + mbi->mmap_addr = ptrdest; + mbi->flags |= MULTIBOOT_INFO_MEM_MAP; + ptrorig += mmap_size; + ptrdest += mmap_size; + + /* Convert from bytes to kilobytes. */ + mbi->mem_lower = grub_mmap_get_lower () / 1024; + mbi->mem_upper = grub_mmap_get_upper () / 1024; + mbi->flags |= MULTIBOOT_INFO_MEMORY; + + if (bootdev_set) + { + mbi->boot_device = bootdev; + mbi->flags |= MULTIBOOT_INFO_BOOTDEV; + } + + return GRUB_ERR_NONE; +} + +void +grub_multiboot_free_mbi (void) +{ + struct module *cur, *next; + + cmdline_size = 0; + total_modcmd = 0; + modcnt = 0; + grub_free (cmdline); + cmdline = NULL; + bootdev_set = 0; + + for (cur = modules; cur; cur = next) + { + next = cur->next; + grub_free (cur->cmdline); + grub_free (cur); + } + modules = NULL; + modules_last = NULL; +} + +grub_err_t +grub_multiboot_init_mbi (int argc, char *argv[]) +{ + grub_ssize_t len = 0; + char *p; + int i; + + grub_multiboot_free_mbi (); + + for (i = 0; i < argc; i++) + len += grub_strlen (argv[i]) + 1; + if (len == 0) + len = 1; + + cmdline = p = grub_malloc (len); + if (! cmdline) + return grub_errno; + cmdline_size = len; + + for (i = 0; i < argc; i++) + { + p = grub_stpcpy (p, argv[i]); + *(p++) = ' '; + } + + /* Remove the space after the last word. */ + if (p != cmdline) + p--; + *p = '\0'; + + return GRUB_ERR_NONE; +} + +grub_err_t +grub_multiboot_add_module (grub_addr_t start, grub_size_t size, + int argc, char *argv[]) +{ + struct module *newmod; + char *p; + grub_ssize_t len = 0; + int i; + + newmod = grub_malloc (sizeof (*newmod)); + if (!newmod) + return grub_errno; + newmod->start = start; + newmod->size = size; + + for (i = 0; i < argc; i++) + len += grub_strlen (argv[i]) + 1; + + if (len == 0) + len = 1; + + newmod->cmdline = p = grub_malloc (len); + if (! newmod->cmdline) + { + grub_free (newmod); + return grub_errno; + } + newmod->cmdline_size = len; + total_modcmd += ALIGN_UP (len, 4); + + for (i = 0; i < argc; i++) + { + p = grub_stpcpy (p, argv[i]); + *(p++) = ' '; + } + + /* Remove the space after the last word. */ + if (p != newmod->cmdline) + p--; + *p = '\0'; + + if (modules_last) + modules_last->next = newmod; + else + { + modules = newmod; + modules_last->next = NULL; + } + modules_last = newmod; + + modcnt++; + + return GRUB_ERR_NONE; +} + +void +grub_multiboot_set_bootdev (void) +{ + char *p; + grub_uint32_t biosdev, slice = ~0, part = ~0; + grub_device_t dev; + +#ifdef GRUB_MACHINE_PCBIOS + biosdev = grub_get_root_biosnumber (); +#else + biosdev = 0xffffffff; +#endif + + dev = grub_device_open (0); + if (dev && dev->disk && dev->disk->partition) + { + + p = dev->disk->partition->partmap->get_name (dev->disk->partition); + if (p) + { + if ((p[0] >= '0') && (p[0] <= '9')) + { + slice = grub_strtoul (p, &p, 0) - 1; + + if ((p) && (p[0] == ',')) + p++; + } + + if ((p[0] >= 'a') && (p[0] <= 'z')) + part = p[0] - 'a'; + } + } + if (dev) + grub_device_close (dev); + + bootdev = ((biosdev & 0xff) << 24) | ((slice & 0xff) << 16) + | ((part & 0xff) << 8) | 0xff; + bootdev_set = 1; +} From b16ff4662ea7a3d3187499c435c3b45a85af7563 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Tue, 12 Jan 2010 19:47:02 +0100 Subject: [PATCH 2/2] Small cleanup --- loader/i386/multiboot.c | 26 -------------------------- loader/i386/multiboot_elfxx.c | 2 +- 2 files changed, 1 insertion(+), 27 deletions(-) diff --git a/loader/i386/multiboot.c b/loader/i386/multiboot.c index 2a69327b4..5dc304117 100644 --- a/loader/i386/multiboot.c +++ b/loader/i386/multiboot.c @@ -232,32 +232,6 @@ grub_multiboot (int argc, char *argv[]) else if (grub_multiboot_load_elf (file, buffer) != GRUB_ERR_NONE) goto fail; - if (header->flags & MULTIBOOT_VIDEO_MODE) - { - switch (header->mode_type) - { - case 1: - grub_env_set ("gfxpayload", "text"); - break; - - case 0: - { - char buf[sizeof ("XXXXXXXXXXxXXXXXXXXXXxXXXXXXXXXX,XXXXXXXXXXxXXXXXXXXXX,auto")]; - if (header->depth && header->width && header->height) - grub_sprintf (buf, "%dx%dx%d,%dx%d,auto", header->width, - header->height, header->depth, header->width, - header->height); - else if (header->width && header->height) - grub_sprintf (buf, "%dx%d,auto", header->width, header->height); - else - grub_sprintf (buf, "auto"); - - grub_env_set ("gfxpayload", buf); - break; - } - } - } - grub_multiboot_set_bootdev (); grub_loader_set (grub_multiboot_boot, grub_multiboot_unload, 0); diff --git a/loader/i386/multiboot_elfxx.c b/loader/i386/multiboot_elfxx.c index 8f6367432..2e35183a4 100644 --- a/loader/i386/multiboot_elfxx.c +++ b/loader/i386/multiboot_elfxx.c @@ -104,7 +104,7 @@ CONCAT(grub_multiboot_load_elf, XX) (grub_file_t file, void *buffer) alloc_mbi = grub_multiboot_get_mbi_size (); grub_multiboot_payload_orig - = grub_relocator32_alloc (grub_multiboot_pure_size + alloc_mbi); + = grub_relocator32_alloc (grub_multiboot_pure_size + alloc_mbi + 65536); if (!grub_multiboot_payload_orig) return grub_errno;