* grub-core/loader/multiboot.c: Add support for multiboot kernels
quirks.
This commit is contained in:
parent
81afc5cce6
commit
00bfa988fc
6 changed files with 137 additions and 54 deletions
|
@ -1,3 +1,8 @@
|
|||
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
|
||||
|
|
|
@ -3680,6 +3680,8 @@ you forget a command, you can run the command @command{help}
|
|||
* 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
|
||||
|
@ -4369,7 +4371,6 @@ List loaded fonts.
|
|||
Show list of loaded modules.
|
||||
@end deffn
|
||||
|
||||
|
||||
@node md5sum
|
||||
@subsection md5sum
|
||||
|
||||
|
@ -4378,6 +4379,34 @@ Alias for @code{hashsum --hash md5 arg @dots{}}. See command @command{hashsum}
|
|||
(@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
|
||||
|
|
|
@ -58,7 +58,63 @@ static int bootdev_set;
|
|||
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)
|
||||
|
@ -106,59 +162,11 @@ grub_multiboot_load (grub_file_t file, const char *filename)
|
|||
"unsupported flag: 0x%x", header->flags);
|
||||
}
|
||||
|
||||
if (header->flags & MULTIBOOT_AOUT_KLUDGE)
|
||||
err = load_kernel (file, filename, buffer, header);
|
||||
if (err)
|
||||
{
|
||||
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 = 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)
|
||||
|
|
|
@ -160,6 +160,8 @@ grub_multiboot_unload (void)
|
|||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static grub_uint64_t highest_load;
|
||||
|
||||
#define MULTIBOOT_LOAD_ELF64
|
||||
#include "multiboot_elfxx.c"
|
||||
#undef MULTIBOOT_LOAD_ELF64
|
||||
|
@ -240,6 +242,26 @@ grub_cmd_multiboot (grub_command_t cmd __attribute__ ((unused)),
|
|||
|
||||
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"));
|
||||
|
||||
|
@ -290,6 +312,7 @@ grub_cmd_module (grub_command_t cmd __attribute__ ((unused)),
|
|||
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"));
|
||||
|
@ -315,12 +338,17 @@ grub_cmd_module (grub_command_t cmd __attribute__ ((unused)),
|
|||
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)
|
||||
|
|
|
@ -86,6 +86,9 @@ CONCAT(grub_multiboot_load_elf, XX) (grub_file_t file, const char *filename, voi
|
|||
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);
|
||||
|
||||
|
|
|
@ -34,6 +34,16 @@
|
|||
#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[]);
|
||||
|
|
Loading…
Reference in a new issue