quirks.
+2013-10-28 Vladimir Serbinenko <phcoder@gmail.com>
+
+ * grub-core/loader/multiboot.c: Add support for multiboot kernels
+ quirks.
+
2013-10-28 Vladimir Serbinenko <phcoder@gmail.com>
* grub-core/loader/i386/linux.c (allocate_pages): Allocate at least
* lsfonts:: List loaded fonts
* lsmod:: Show loaded modules
* md5sum:: Compute or check MD5 hash
+* module:: Load module for multiboot kernel
+* multiboot:: Load multiboot compliant kernel
* nativedisk:: Switch to native disk drivers
* normal:: Enter normal mode
* normal_exit:: Exit from normal mode
Show list of loaded modules.
@end deffn
-
@node md5sum
@subsection md5sum
(@pxref{hashsum}) for full description.
@end deffn
+@node module
+@subsection module
+
+@deffn Command module [--nounzip] file [arguments]
+Load a module for multiboot kernel image. The rest of the
+line is passed verbatim as the module command line.
+@end deffn
+
+@node multiboot
+@subsection multiboot
+
+@deffn Command multiboot [--quirk-bad-kludge] [--quirk-modules-after-kernel] file @dots{}
+Load a multiboot kernel image from @var{file}. The rest of the
+line is passed verbatim as the @dfn{kernel command-line}. Any module must
+be reloaded after using this command (@pxref{module}).
+
+Some kernels have known problems. You need to specify --quirk-* for those.
+--quirk-bad-kludge is a problem seen in several products that they include
+loading kludge information with invalid data in ELF file. GRUB prior to 0.97
+and some custom builds prefered ELF information while 0.97 and GRUB 2
+use kludge. Use this option to ignore kludge.
+Known affected systems: old Solaris, SkyOS.
+
+--quirk-modules-after-kernel is needed for kernels which load at relatively
+high address e.g. 16MiB mark and can't cope with modules stuffed between
+1MiB mark and beginning of the kernel.
+Known afftected systems: VMWare.
+@end deffn
@node nativedisk
@subsection nativedisk
static grub_size_t elf_sec_num, elf_sec_entsize;
static unsigned elf_sec_shstrndx;
static void *elf_sections;
+grub_multiboot_quirks_t grub_multiboot_quirks;
+static grub_err_t
+load_kernel (grub_file_t file, const char *filename,
+ char *buffer, struct multiboot_header *header)
+{
+ grub_err_t err;
+ if (grub_multiboot_quirks & GRUB_MULTIBOOT_QUIRK_BAD_KLUDGE)
+ {
+ err = grub_multiboot_load_elf (file, filename, buffer);
+ if (err == GRUB_ERR_UNKNOWN_OS && (header->flags & MULTIBOOT_AOUT_KLUDGE))
+ grub_errno = err = GRUB_ERR_NONE;
+ }
+ if (header->flags & MULTIBOOT_AOUT_KLUDGE)
+ {
+ int offset = ((char *) header - buffer -
+ (header->header_addr - header->load_addr));
+ int load_size = ((header->load_end_addr == 0) ? file->size - offset :
+ header->load_end_addr - header->load_addr);
+ grub_size_t code_size;
+ void *source;
+ grub_relocator_chunk_t ch;
+
+ if (header->bss_end_addr)
+ code_size = (header->bss_end_addr - header->load_addr);
+ else
+ code_size = load_size;
+
+ err = grub_relocator_alloc_chunk_addr (grub_multiboot_relocator,
+ &ch, header->load_addr,
+ code_size);
+ if (err)
+ {
+ grub_dprintf ("multiboot_loader", "Error loading aout kludge\n");
+ return err;
+ }
+ source = get_virtual_current_address (ch);
+
+ if ((grub_file_seek (file, offset)) == (grub_off_t) -1)
+ {
+ return grub_errno;
+ }
+
+ grub_file_read (file, source, load_size);
+ if (grub_errno)
+ return grub_errno;
+
+ if (header->bss_end_addr)
+ grub_memset ((grub_uint8_t *) source + load_size, 0,
+ header->bss_end_addr - header->load_addr - load_size);
+
+ grub_multiboot_payload_eip = header->entry_addr;
+ return GRUB_ERR_NONE;
+ }
+
+ return grub_multiboot_load_elf (file, filename, buffer);
+}
grub_err_t
grub_multiboot_load (grub_file_t file, const char *filename)
"unsupported flag: 0x%x", header->flags);
}
- if (header->flags & MULTIBOOT_AOUT_KLUDGE)
- {
- int offset = ((char *) header - buffer -
- (header->header_addr - header->load_addr));
- int load_size = ((header->load_end_addr == 0) ? file->size - offset :
- header->load_end_addr - header->load_addr);
- grub_size_t code_size;
- void *source;
- grub_relocator_chunk_t ch;
-
- if (header->bss_end_addr)
- code_size = (header->bss_end_addr - header->load_addr);
- else
- code_size = load_size;
-
- err = grub_relocator_alloc_chunk_addr (grub_multiboot_relocator,
- &ch, header->load_addr,
- code_size);
- if (err)
- {
- grub_dprintf ("multiboot_loader", "Error loading aout kludge\n");
- grub_free (buffer);
- return err;
- }
- source = get_virtual_current_address (ch);
-
- if ((grub_file_seek (file, offset)) == (grub_off_t) -1)
- {
- grub_free (buffer);
- return grub_errno;
- }
-
- grub_file_read (file, source, load_size);
- if (grub_errno)
- {
- grub_free (buffer);
- return grub_errno;
- }
-
- if (header->bss_end_addr)
- grub_memset ((grub_uint8_t *) source + load_size, 0,
- header->bss_end_addr - header->load_addr - load_size);
-
- grub_multiboot_payload_eip = header->entry_addr;
- }
- else
+ err = load_kernel (file, filename, buffer, header);
+ if (err)
{
- err = grub_multiboot_load_elf (file, filename, buffer);
- if (err)
- {
- grub_free (buffer);
- return err;
- }
+ grub_free (buffer);
+ return err;
}
if (header->flags & MULTIBOOT_VIDEO_MODE)
return GRUB_ERR_NONE;
}
+static grub_uint64_t highest_load;
+
#define MULTIBOOT_LOAD_ELF64
#include "multiboot_elfxx.c"
#undef MULTIBOOT_LOAD_ELF64
grub_loader_unset ();
+ highest_load = 0;
+
+#ifndef GRUB_USE_MULTIBOOT2
+ grub_multiboot_quirks = GRUB_MULTIBOOT_QUIRKS_NONE;
+
+ if (argc != 0 && grub_strcmp (argv[0], "--quirk-bad-kludge") == 0)
+ {
+ argc--;
+ argv++;
+ grub_multiboot_quirks |= GRUB_MULTIBOOT_QUIRK_BAD_KLUDGE;
+ }
+
+ if (argc != 0 && grub_strcmp (argv[0], "--quirk-modules-after-kernel") == 0)
+ {
+ argc--;
+ argv++;
+ grub_multiboot_quirks |= GRUB_MULTIBOOT_QUIRK_MODULES_AFTER_KERNEL;
+ }
+#endif
+
if (argc == 0)
return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
grub_addr_t target;
grub_err_t err;
int nounzip = 0;
+ grub_uint64_t lowest_addr = 0;
if (argc == 0)
return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
if (! file)
return grub_errno;
+#ifndef GRUB_USE_MULTIBOOT2
+ if (grub_multiboot_quirks & GRUB_MULTIBOOT_QUIRK_MODULES_AFTER_KERNEL)
+ lowest_addr = ALIGN_UP (highest_load + 1048576, 4096);
+#endif
+
size = grub_file_size (file);
if (size)
{
grub_relocator_chunk_t ch;
err = grub_relocator_alloc_chunk_align (grub_multiboot_relocator, &ch,
- 0, (0xffffffff - size) + 1,
+ lowest_addr, (0xffffffff - size) + 1,
size, MULTIBOOT_MOD_ALIGN,
GRUB_RELOCATOR_PREFERENCE_NONE, 0);
if (err)
grub_err_t err;
void *source;
+ if (phdr(i)->p_paddr + phdr(i)->p_memsz > highest_load)
+ highest_load = phdr(i)->p_paddr + phdr(i)->p_memsz;
+
grub_dprintf ("multiboot_loader", "segment %d: paddr=0x%lx, memsz=0x%lx, vaddr=0x%lx\n",
i, (long) phdr(i)->p_paddr, (long) phdr(i)->p_memsz, (long) phdr(i)->p_vaddr);
#include <grub/types.h>
#include <grub/err.h>
+#ifndef GRUB_USE_MULTIBOOT2
+typedef enum
+ {
+ GRUB_MULTIBOOT_QUIRKS_NONE = 0,
+ GRUB_MULTIBOOT_QUIRK_BAD_KLUDGE = 1,
+ GRUB_MULTIBOOT_QUIRK_MODULES_AFTER_KERNEL = 2
+ } grub_multiboot_quirks_t;
+extern grub_multiboot_quirks_t grub_multiboot_quirks;
+#endif
+
extern struct grub_relocator *grub_multiboot_relocator;
void grub_multiboot (int argc, char *argv[]);