* grub-core/loader/multiboot.c: Add support for multiboot kernels

quirks.
This commit is contained in:
Vladimir Serbinenko 2013-10-28 15:23:46 +01:00
parent 81afc5cce6
commit 00bfa988fc
6 changed files with 137 additions and 54 deletions

View file

@ -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)

View file

@ -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)

View file

@ -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);