merge mainline

This commit is contained in:
Colin Watson 2010-06-12 12:17:28 +01:00
commit 934302d00b
545 changed files with 51148 additions and 23539 deletions

View file

@ -140,7 +140,6 @@ grub_bsd_get_device (grub_uint32_t * biosdev,
grub_uint32_t * unit,
grub_uint32_t * slice, grub_uint32_t * part)
{
char *p;
grub_device_t dev;
#ifdef GRUB_MACHINE_PCBIOS
@ -154,21 +153,13 @@ grub_bsd_get_device (grub_uint32_t * biosdev,
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 (dev->disk->partition->parent)
{
if ((p[0] >= '0') && (p[0] <= '9'))
{
*slice = grub_strtoul (p, &p, 0);
if ((p) && (p[0] == ','))
p++;
}
if ((p[0] >= 'a') && (p[0] <= 'z'))
*part = p[0] - 'a';
*part = dev->disk->partition->number;
*slice = dev->disk->partition->parent->number + 1;
}
else
*slice = dev->disk->partition->number + 1;
}
if (dev)
grub_device_close (dev);
@ -461,14 +452,14 @@ grub_freebsd_boot (void)
}
grub_memset (&bi, 0, sizeof (bi));
bi.bi_version = FREEBSD_BOOTINFO_VERSION;
bi.bi_size = sizeof (bi);
bi.version = FREEBSD_BOOTINFO_VERSION;
bi.length = sizeof (bi);
grub_bsd_get_device (&biosdev, &unit, &slice, &part);
bootdev = (FREEBSD_B_DEVMAGIC + ((slice + 1) << FREEBSD_B_SLICESHIFT) +
(unit << FREEBSD_B_UNITSHIFT) + (part << FREEBSD_B_PARTSHIFT));
bi.bi_bios_dev = biosdev;
bi.boot_device = biosdev;
p = (char *) kern_end;
@ -478,7 +469,7 @@ grub_freebsd_boot (void)
{
*(p++) = 0;
bi.bi_envp = kern_end;
bi.environment = kern_end;
kern_end = ALIGN_PAGE ((grub_uint32_t) p);
}
@ -491,23 +482,23 @@ grub_freebsd_boot (void)
return grub_errno;
grub_memcpy ((char *) kern_end, mod_buf, mod_buf_len);
bi.bi_modulep = kern_end;
bi.tags = kern_end;
kern_end = ALIGN_PAGE (kern_end + mod_buf_len);
if (is_64bit)
kern_end += 4096 * 4;
md_ofs = bi.bi_modulep + kern_end_mdofs;
md_ofs = bi.tags + kern_end_mdofs;
ofs = (is_64bit) ? 16 : 12;
*((grub_uint32_t *) md_ofs) = kern_end;
md_ofs -= ofs;
*((grub_uint32_t *) md_ofs) = bi.bi_envp;
*((grub_uint32_t *) md_ofs) = bi.environment;
md_ofs -= ofs;
*((grub_uint32_t *) md_ofs) = bootflags;
}
bi.bi_kernend = kern_end;
bi.kern_end = kern_end;
grub_video_set_mode ("text", 0, 0);
@ -554,12 +545,12 @@ grub_freebsd_boot (void)
&grub_bsd64_trampoline_end - &grub_bsd64_trampoline_start);
/* Launch trampoline. */
launch_trampoline (entry, entry_hi, pagetable, bi.bi_modulep,
launch_trampoline (entry, entry_hi, pagetable, bi.tags,
kern_end);
}
else
grub_unix_real_boot (entry, bootflags | FREEBSD_RB_BOOTINFO, bootdev,
0, 0, 0, &bi, bi.bi_modulep, kern_end);
0, 0, 0, &bi, bi.tags, kern_end);
/* Not reached. */
return GRUB_ERR_NONE;
@ -1145,14 +1136,20 @@ grub_cmd_freebsd_loadenv (grub_command_t cmd __attribute__ ((unused)),
if (*curr)
{
char name[grub_strlen (curr) + sizeof("kFreeBSD.")];
char *name;
if (*p == '"')
p++;
grub_sprintf (name, "kFreeBSD.%s", curr);
if (grub_env_set (name, p))
name = grub_xasprintf ("kFreeBSD.%s", curr);
if (!name)
goto fail;
if (grub_env_set (name, p))
{
grub_free (name);
goto fail;
}
grub_free (name);
}
}

View file

@ -80,7 +80,7 @@ SUFFIX (grub_freebsd_load_elfmodule_obj) (grub_file_t file, int argc,
{
Elf_Ehdr e;
Elf_Shdr *s;
char *shdr;
char *shdr = 0;
grub_addr_t curload, module;
grub_err_t err;
@ -148,7 +148,7 @@ SUFFIX (grub_freebsd_load_elfmodule) (grub_file_t file, int argc, char *argv[],
{
Elf_Ehdr e;
Elf_Shdr *s;
char *shdr;
char *shdr = 0;
grub_addr_t curload, module;
grub_err_t err;
@ -223,7 +223,7 @@ SUFFIX (grub_freebsd_load_elf_meta) (grub_file_t file, grub_addr_t *kern_end)
grub_err_t err;
Elf_Ehdr e;
Elf_Shdr *s;
char *shdr;
char *shdr = 0;
unsigned symoff, stroff, symsize, strsize;
grub_addr_t curload;
grub_freebsd_addr_t symstart, symend, symentsize, dynamic;

View file

@ -1,6 +1,6 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2006,2007,2008,2009 Free Software Foundation, Inc.
* Copyright (C) 2006,2007,2008,2009,2010 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
@ -305,7 +305,8 @@ grub_linux_setup_video (struct linux_kernel_params *params)
params->lfb_line_len = mode_info.pitch;
params->lfb_base = (grub_size_t) framebuffer;
params->lfb_size = (params->lfb_line_len * params->lfb_height + 65535) >> 16;
params->lfb_size = ALIGN_UP (params->lfb_line_len * params->lfb_height,
65536);
params->red_mask_size = mode_info.red_mask_size;
params->red_field_pos = mode_info.red_field_pos;
@ -316,7 +317,7 @@ grub_linux_setup_video (struct linux_kernel_params *params)
params->reserved_mask_size = mode_info.reserved_mask_size;
params->reserved_field_pos = mode_info.reserved_field_pos;
params->have_vga = GRUB_VIDEO_TYPE_EFI;
params->have_vga = GRUB_VIDEO_LINUX_TYPE_SIMPLE;
#ifdef GRUB_MACHINE_PCBIOS
/* VESA packed modes may come with zeroed mask sizes, which need
@ -433,11 +434,9 @@ grub_linux_boot (void)
May change in future if we have modes without framebuffer. */
if (modevar && *modevar != 0)
{
tmp = grub_malloc (grub_strlen (modevar)
+ sizeof (";auto"));
tmp = grub_xasprintf ("%s;auto", modevar);
if (! tmp)
return grub_errno;
grub_sprintf (tmp, "%s;auto", modevar);
err = grub_video_set_mode (tmp, GRUB_VIDEO_MODE_TYPE_PURE_TEXT, 0);
grub_free (tmp);
}
@ -609,8 +608,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
goto fail;
}
/* XXX Linux assumes that only elilo can boot Linux on EFI!!! */
params->type_of_loader = (LINUX_LOADER_ID_ELILO << 4);
params->type_of_loader = (LINUX_LOADER_ID_GRUB << 4);
params->cl_magic = GRUB_LINUX_CL_MAGIC;
params->cl_offset = 0x1000;
@ -783,7 +781,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
else if (grub_memcmp (argv[i], "video=efifb", 11) == 0)
{
if (params->have_vga)
params->have_vga = GRUB_VIDEO_TYPE_EFI;
params->have_vga = GRUB_VIDEO_LINUX_TYPE_SIMPLE;
}
/* Specify the boot file. */

View file

@ -394,12 +394,15 @@ grub_linux_setup_video (struct linux_kernel_params *params)
{
struct grub_video_mode_info mode_info;
void *framebuffer;
int ret;
grub_err_t err;
ret = grub_video_get_info_and_fini (&mode_info, &framebuffer);
err = grub_video_get_info_and_fini (&mode_info, &framebuffer);
if (ret)
return 1;
if (err)
{
grub_errno = GRUB_ERR_NONE;
return 1;
}
params->lfb_width = mode_info.width;
params->lfb_height = mode_info.height;
@ -407,7 +410,7 @@ grub_linux_setup_video (struct linux_kernel_params *params)
params->lfb_line_len = mode_info.pitch;
params->lfb_base = (grub_size_t) framebuffer;
params->lfb_size = (params->lfb_line_len * params->lfb_height + 65535) >> 16;
params->lfb_size = ALIGN_UP (params->lfb_line_len * params->lfb_height, 65536);
params->red_mask_size = mode_info.red_mask_size;
params->red_field_pos = mode_info.red_field_pos;
@ -519,11 +522,9 @@ grub_linux_boot (void)
May change in future if we have modes without framebuffer. */
if (modevar && *modevar != 0)
{
tmp = grub_malloc (grub_strlen (modevar)
+ sizeof (";text"));
tmp = grub_xasprintf ("%s;text", modevar);
if (! tmp)
return grub_errno;
grub_sprintf (tmp, "%s;text", modevar);
err = grub_video_set_mode (tmp, 0, 0);
grub_free (tmp);
}
@ -538,16 +539,22 @@ grub_linux_boot (void)
}
if (! grub_linux_setup_video (params))
params->have_vga = GRUB_VIDEO_TYPE_VLFB;
{
/* Use generic framebuffer unless VESA is known to be supported. */
if (params->have_vga != GRUB_VIDEO_LINUX_TYPE_VESA)
params->have_vga = GRUB_VIDEO_LINUX_TYPE_SIMPLE;
else
params->lfb_size >>= 16;
}
else
{
params->have_vga = GRUB_VIDEO_TYPE_TEXT;
params->have_vga = GRUB_VIDEO_LINUX_TYPE_TEXT;
params->video_width = 80;
params->video_height = 25;
}
/* Initialize these last, because terminal position could be affected by printfs above. */
if (params->have_vga == GRUB_VIDEO_TYPE_TEXT)
if (params->have_vga == GRUB_VIDEO_LINUX_TYPE_TEXT)
{
grub_term_output_t term;
int found = 0;
@ -796,19 +803,22 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
break;
}
buf = grub_malloc (sizeof ("WWWWxHHHHxDD;WWWWxHHHH"));
if (! buf)
goto fail;
/* We can't detect VESA, but user is implicitly telling us that it
is built-in because `vga=' parameter was used. */
params->have_vga = GRUB_VIDEO_LINUX_TYPE_VESA;
linux_mode
= &linux_vesafb_modes[vid_mode - GRUB_LINUX_VID_MODE_VESA_START];
grub_sprintf (buf, "%ux%ux%u,%ux%u",
linux_vesafb_res[linux_mode->res_index].width,
linux_vesafb_res[linux_mode->res_index].height,
linux_mode->depth,
linux_vesafb_res[linux_mode->res_index].width,
linux_vesafb_res[linux_mode->res_index].height);
buf = grub_xasprintf ("%ux%ux%u,%ux%u",
linux_vesafb_res[linux_mode->res_index].width,
linux_vesafb_res[linux_mode->res_index].height,
linux_mode->depth,
linux_vesafb_res[linux_mode->res_index].width,
linux_vesafb_res[linux_mode->res_index].height);
if (! buf)
goto fail;
grub_printf ("%s is deprecated. "
"Use set gfxpayload=%s before "
"linux command instead.\n",

View file

@ -1,331 +0,0 @@
/* multiboot.c - boot a multiboot OS image. */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2007,2008,2009,2010 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 <http://www.gnu.org/licenses/>.
*/
/*
* FIXME: The following features from the Multiboot specification still
* need to be implemented:
* - VBE support
* - symbol table
* - drives table
* - ROM configuration table
* - APM table
*/
/* The bits in the required part of flags field we don't support. */
#define UNSUPPORTED_FLAGS 0x0000fff8
#include <grub/loader.h>
#include <grub/machine/loader.h>
#include <grub/multiboot.h>
#include <grub/cpu/multiboot.h>
#include <grub/elf.h>
#include <grub/aout.h>
#include <grub/file.h>
#include <grub/err.h>
#include <grub/dl.h>
#include <grub/mm.h>
#include <grub/misc.h>
#include <grub/gzio.h>
#include <grub/env.h>
#include <grub/i386/relocator.h>
#include <grub/video.h>
#ifdef GRUB_MACHINE_EFI
#include <grub/efi/efi.h>
#endif
extern grub_dl_t my_mod;
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_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,
.ecx = 0,
.edx = 0,
.eip = grub_multiboot_payload_eip,
/* Set esp to some random location in low memory to avoid breaking
non-compliant kernels. */
.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;
#ifdef GRUB_MACHINE_EFI
if (! grub_efi_finish_boot_services ())
grub_fatal ("cannot exit boot services");
#endif
grub_relocator32_boot (grub_multiboot_payload_orig,
grub_multiboot_payload_dest,
state);
/* Not reached. */
return GRUB_ERR_NONE;
}
static grub_err_t
grub_multiboot_unload (void)
{
grub_multiboot_free_mbi ();
grub_relocator32_free (grub_multiboot_payload_orig);
alloc_mbi = 0;
grub_multiboot_payload_orig = NULL;
grub_dl_unref (my_mod);
return GRUB_ERR_NONE;
}
#define MULTIBOOT_LOAD_ELF64
#include "multiboot_elfxx.c"
#undef MULTIBOOT_LOAD_ELF64
#define MULTIBOOT_LOAD_ELF32
#include "multiboot_elfxx.c"
#undef MULTIBOOT_LOAD_ELF32
/* Load ELF32 or ELF64. */
static grub_err_t
grub_multiboot_load_elf (grub_file_t file, void *buffer)
{
if (grub_multiboot_is_elf32 (buffer))
return grub_multiboot_load_elf32 (file, buffer);
else if (grub_multiboot_is_elf64 (buffer))
return grub_multiboot_load_elf64 (file, buffer);
return grub_error (GRUB_ERR_UNKNOWN_OS, "unknown ELF class");
}
void
grub_multiboot (int argc, char *argv[])
{
grub_file_t file = 0;
char buffer[MULTIBOOT_SEARCH];
struct multiboot_header *header;
grub_ssize_t len;
grub_loader_unset ();
if (argc == 0)
{
grub_error (GRUB_ERR_BAD_ARGUMENT, "no kernel specified");
goto fail;
}
file = grub_gzfile_open (argv[0], 1);
if (! file)
{
grub_error (GRUB_ERR_BAD_ARGUMENT, "couldn't open file");
goto fail;
}
len = grub_file_read (file, buffer, MULTIBOOT_SEARCH);
if (len < 32)
{
grub_error (GRUB_ERR_BAD_OS, "file too small");
goto fail;
}
/* Look for the multiboot header in the buffer. The header should
be at least 12 bytes and aligned on a 4-byte boundary. */
for (header = (struct multiboot_header *) buffer;
((char *) header <= buffer + len - 12) || (header = 0);
header = (struct multiboot_header *) ((char *) header + 4))
{
if (header->magic == MULTIBOOT_HEADER_MAGIC
&& !(header->magic + header->flags + header->checksum))
break;
}
if (header == 0)
{
grub_error (GRUB_ERR_BAD_ARGUMENT, "no multiboot header found");
goto fail;
}
if (header->flags & UNSUPPORTED_FLAGS)
{
grub_error (GRUB_ERR_UNKNOWN_OS,
"unsupported flag: 0x%x", header->flags);
goto fail;
}
grub_relocator32_free (grub_multiboot_payload_orig);
grub_multiboot_payload_orig = NULL;
/* Skip filename. */
grub_multiboot_init_mbi (argc - 1, argv + 1);
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);
if (header->bss_end_addr)
code_size = (header->bss_end_addr - header->load_addr);
else
code_size = load_size;
grub_multiboot_payload_dest = header->load_addr;
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_pure_size + alloc_mbi);
if (! grub_multiboot_payload_orig)
goto fail;
if ((grub_file_seek (file, offset)) == (grub_off_t) -1)
goto fail;
grub_file_read (file, (void *) grub_multiboot_payload_orig, load_size);
if (grub_errno)
goto fail;
if (header->bss_end_addr)
grub_memset ((void *) (grub_multiboot_payload_orig + load_size), 0,
header->bss_end_addr - header->load_addr - load_size);
grub_multiboot_payload_eip = header->entry_addr;
}
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_accepts_video (!!(header->flags & MULTIBOOT_VIDEO_MODE));
grub_multiboot_set_bootdev ();
grub_loader_set (grub_multiboot_boot, grub_multiboot_unload, 0);
fail:
if (file)
grub_file_close (file);
if (grub_errno != GRUB_ERR_NONE)
{
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;
char *module = 0;
grub_err_t err;
if (argc == 0)
{
grub_error (GRUB_ERR_BAD_ARGUMENT, "no module specified");
goto fail;
}
if (!grub_multiboot_payload_orig)
{
grub_error (GRUB_ERR_BAD_ARGUMENT,
"you need to load the multiboot kernel first");
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;
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;
}
fail:
if (file)
grub_file_close (file);
}

View file

@ -1,159 +0,0 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#if defined(MULTIBOOT_LOAD_ELF32)
# define XX 32
# define E_MACHINE EM_386
# define ELFCLASSXX ELFCLASS32
# define Elf_Ehdr Elf32_Ehdr
# define Elf_Phdr Elf32_Phdr
#elif defined(MULTIBOOT_LOAD_ELF64)
# define XX 64
# define E_MACHINE EM_X86_64
# define ELFCLASSXX ELFCLASS64
# define Elf_Ehdr Elf64_Ehdr
# define Elf_Phdr Elf64_Phdr
#else
#error "I'm confused"
#endif
#include <grub/i386/relocator.h>
#define CONCAT(a,b) CONCAT_(a, b)
#define CONCAT_(a,b) a ## b
/* Check if BUFFER contains ELF32 (or ELF64). */
static int
CONCAT(grub_multiboot_is_elf, XX) (void *buffer)
{
Elf_Ehdr *ehdr = (Elf_Ehdr *) buffer;
return ehdr->e_ident[EI_CLASS] == ELFCLASSXX;
}
static grub_err_t
CONCAT(grub_multiboot_load_elf, XX) (grub_file_t file, void *buffer)
{
Elf_Ehdr *ehdr = (Elf_Ehdr *) buffer;
char *phdr_base;
int lowest_segment = -1, highest_segment = -1;
int i;
if (ehdr->e_ident[EI_CLASS] != ELFCLASSXX)
return grub_error (GRUB_ERR_UNKNOWN_OS, "invalid ELF class");
if (ehdr->e_ident[EI_MAG0] != ELFMAG0
|| ehdr->e_ident[EI_MAG1] != ELFMAG1
|| ehdr->e_ident[EI_MAG2] != ELFMAG2
|| ehdr->e_ident[EI_MAG3] != ELFMAG3
|| ehdr->e_version != EV_CURRENT
|| ehdr->e_ident[EI_DATA] != ELFDATA2LSB
|| ehdr->e_machine != E_MACHINE)
return grub_error(GRUB_ERR_UNKNOWN_OS, "no valid ELF header found");
if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN)
return grub_error (GRUB_ERR_UNKNOWN_OS, "invalid ELF file type");
/* FIXME: Should we support program headers at strange locations? */
if (ehdr->e_phoff + ehdr->e_phnum * ehdr->e_phentsize > MULTIBOOT_SEARCH)
return grub_error (GRUB_ERR_BAD_OS, "program header at a too high offset");
#ifdef MULTIBOOT_LOAD_ELF64
/* We still in 32-bit mode. */
if (ehdr->e_entry > 0xffffffff)
return grub_error (GRUB_ERR_BAD_OS, "invalid entry point for ELF64");
#endif
phdr_base = (char *) buffer + ehdr->e_phoff;
#define phdr(i) ((Elf_Phdr *) (phdr_base + (i) * ehdr->e_phentsize))
for (i = 0; i < ehdr->e_phnum; i++)
if (phdr(i)->p_type == PT_LOAD && phdr(i)->p_filesz != 0)
{
/* Beware that segment 0 isn't necessarily loadable */
if (lowest_segment == -1
|| phdr(i)->p_paddr < phdr(lowest_segment)->p_paddr)
lowest_segment = i;
if (highest_segment == -1
|| phdr(i)->p_paddr > phdr(highest_segment)->p_paddr)
highest_segment = i;
}
if (lowest_segment == -1)
return grub_error (GRUB_ERR_BAD_OS, "ELF contains no loadable segments");
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_pure_size += code_size;
alloc_mbi = grub_multiboot_get_mbi_size ();
grub_multiboot_payload_orig
= grub_relocator32_alloc (grub_multiboot_pure_size + alloc_mbi + 65536);
if (!grub_multiboot_payload_orig)
return grub_errno;
/* Load every loadable segment in memory. */
for (i = 0; i < ehdr->e_phnum; i++)
{
if (phdr(i)->p_type == PT_LOAD && phdr(i)->p_filesz != 0)
{
char *load_this_module_at = (char *) (grub_multiboot_payload_orig + (long) (phdr(i)->p_paddr - phdr(lowest_segment)->p_paddr));
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);
if (grub_file_seek (file, (grub_off_t) phdr(i)->p_offset)
== (grub_off_t) -1)
return grub_error (GRUB_ERR_BAD_OS,
"invalid offset in program header");
if (grub_file_read (file, load_this_module_at, phdr(i)->p_filesz)
!= (grub_ssize_t) phdr(i)->p_filesz)
return grub_error (GRUB_ERR_BAD_OS,
"couldn't read segment from file");
if (phdr(i)->p_filesz < phdr(i)->p_memsz)
grub_memset (load_this_module_at + phdr(i)->p_filesz, 0,
phdr(i)->p_memsz - phdr(i)->p_filesz);
}
}
for (i = 0; i < ehdr->e_phnum; i++)
if (phdr(i)->p_vaddr <= ehdr->e_entry
&& phdr(i)->p_vaddr + phdr(i)->p_memsz > ehdr->e_entry)
{
grub_multiboot_payload_eip = grub_multiboot_payload_dest
+ (ehdr->e_entry - phdr(i)->p_vaddr) + (phdr(i)->p_paddr - phdr(lowest_segment)->p_paddr);
break;
}
if (i == ehdr->e_phnum)
return grub_error (GRUB_ERR_BAD_OS, "entry point isn't in a segment");
#undef phdr
return grub_errno;
}
#undef XX
#undef E_MACHINE
#undef ELFCLASSXX
#undef Elf_Ehdr
#undef Elf_Phdr

View file

@ -23,6 +23,7 @@
#endif
#include <grub/multiboot.h>
#include <grub/cpu/multiboot.h>
#include <grub/cpu/relocator.h>
#include <grub/disk.h>
#include <grub/device.h>
#include <grub/partition.h>
@ -30,15 +31,10 @@
#include <grub/misc.h>
#include <grub/env.h>
#include <grub/video.h>
#include <grub/file.h>
#if defined (GRUB_MACHINE_PCBIOS) || defined (GRUB_MACHINE_COREBOOT) || defined (GRUB_MACHINE_QEMU)
#include <grub/i386/pc/vbe.h>
#define DEFAULT_VIDEO_MODE "text"
#define HAS_VGA_TEXT 1
#else
#define DEFAULT_VIDEO_MODE "auto"
#define HAS_VGA_TEXT 0
#endif
/* The bits in the required part of flags field we don't support. */
#define UNSUPPORTED_FLAGS 0x0000fff8
struct module
{
@ -56,33 +52,136 @@ static unsigned modcnt;
static char *cmdline = NULL;
static grub_uint32_t bootdev;
static int bootdev_set;
static int accepts_video;
void
grub_multiboot_set_accepts_video (int val)
grub_err_t
grub_multiboot_load (grub_file_t file)
{
accepts_video = val;
}
char *buffer;
grub_ssize_t len;
struct multiboot_header *header;
grub_err_t err;
/* 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;
buffer = grub_malloc (MULTIBOOT_SEARCH);
if (!buffer)
return grub_errno;
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)))
len = grub_file_read (file, buffer, MULTIBOOT_SEARCH);
if (len < 32)
{
count++;
return 0;
grub_free (buffer);
return grub_error (GRUB_ERR_BAD_OS, "file too small");
}
grub_mmap_iterate (hook);
/* Look for the multiboot header in the buffer. The header should
be at least 12 bytes and aligned on a 4-byte boundary. */
for (header = (struct multiboot_header *) buffer;
((char *) header <= buffer + len - 12) || (header = 0);
header = (struct multiboot_header *) ((char *) header + MULTIBOOT_HEADER_ALIGN))
{
if (header->magic == MULTIBOOT_HEADER_MAGIC
&& !(header->magic + header->flags + header->checksum))
break;
}
return count * sizeof (struct multiboot_mmap_entry);
if (header == 0)
{
grub_free (buffer);
return grub_error (GRUB_ERR_BAD_ARGUMENT, "no multiboot header found");
}
if (header->flags & UNSUPPORTED_FLAGS)
{
grub_free (buffer);
return grub_error (GRUB_ERR_UNKNOWN_OS,
"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;
if (header->bss_end_addr)
code_size = (header->bss_end_addr - header->load_addr);
else
code_size = load_size;
grub_multiboot_payload_dest = header->load_addr;
grub_multiboot_pure_size += code_size;
/* Allocate a bit more to avoid relocations in most cases. */
grub_multiboot_alloc_mbi = grub_multiboot_get_mbi_size () + 65536;
grub_multiboot_payload_orig
= grub_relocator32_alloc (grub_multiboot_pure_size + grub_multiboot_alloc_mbi);
if (! grub_multiboot_payload_orig)
{
grub_free (buffer);
return grub_errno;
}
if ((grub_file_seek (file, offset)) == (grub_off_t) -1)
{
grub_free (buffer);
return grub_errno;
}
grub_file_read (file, (void *) grub_multiboot_payload_orig, load_size);
if (grub_errno)
{
grub_free (buffer);
return grub_errno;
}
if (header->bss_end_addr)
grub_memset ((void *) (grub_multiboot_payload_orig + 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, buffer);
if (err)
{
grub_free (buffer);
return err;
}
}
if (header->flags & MULTIBOOT_VIDEO_MODE)
{
switch (header->mode_type)
{
case 1:
err = grub_multiboot_set_console (GRUB_MULTIBOOT_CONSOLE_EGA_TEXT,
GRUB_MULTIBOOT_CONSOLE_EGA_TEXT
| GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER,
0, 0, 0, 0);
break;
case 0:
err = grub_multiboot_set_console (GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER,
GRUB_MULTIBOOT_CONSOLE_EGA_TEXT
| GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER,
header->width, header->height,
header->depth, 0);
break;
default:
err = grub_error (GRUB_ERR_BAD_OS,
"unsupported graphical mode type %d",
header->mode_type);
break;
}
}
else
err = grub_multiboot_set_console (GRUB_MULTIBOOT_CONSOLE_EGA_TEXT,
GRUB_MULTIBOOT_CONSOLE_EGA_TEXT,
0, 0, 0, 0);
return err;
}
grub_size_t
@ -90,7 +189,8 @@ 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 ()
+ ALIGN_UP (sizeof(PACKAGE_STRING), 4)
+ grub_get_multiboot_mmap_count () * sizeof (struct multiboot_mmap_entry)
+ 256 * sizeof (struct multiboot_color);
}
@ -110,6 +210,18 @@ grub_fill_multiboot_mmap (struct multiboot_mmap_entry *first_entry)
case GRUB_MACHINE_MEMORY_AVAILABLE:
mmap_entry->type = MULTIBOOT_MEMORY_AVAILABLE;
break;
#ifdef GRUB_MACHINE_MEMORY_ACPI_RECLAIMABLE
case GRUB_MACHINE_MEMORY_ACPI_RECLAIMABLE:
mmap_entry->type = MULTIBOOT_MEMORY_ACPI_RECLAIMABLE;
break;
#endif
#ifdef GRUB_MACHINE_MEMORY_NVS
case GRUB_MACHINE_MEMORY_NVS:
mmap_entry->type = MULTIBOOT_MEMORY_NVS;
break;
#endif
default:
mmap_entry->type = MULTIBOOT_MEMORY_RESERVED;
@ -124,35 +236,6 @@ grub_fill_multiboot_mmap (struct multiboot_mmap_entry *first_entry)
grub_mmap_iterate (hook);
}
static grub_err_t
set_video_mode (void)
{
grub_err_t err;
const char *modevar;
if (accepts_video || !HAS_VGA_TEXT)
{
modevar = grub_env_get ("gfxpayload");
if (! modevar || *modevar == 0)
err = grub_video_set_mode (DEFAULT_VIDEO_MODE, 0, 0);
else
{
char *tmp;
tmp = grub_malloc (grub_strlen (modevar)
+ sizeof (DEFAULT_VIDEO_MODE) + 1);
if (! tmp)
return grub_errno;
grub_sprintf (tmp, "%s;" DEFAULT_VIDEO_MODE, modevar);
err = grub_video_set_mode (tmp, 0, 0);
grub_free (tmp);
}
}
else
err = grub_video_set_mode ("text", 0, 0);
return err;
}
static grub_err_t
retrieve_video_parameters (struct multiboot_info *mbi,
grub_uint8_t *ptrorig, grub_uint32_t ptrdest)
@ -163,7 +246,7 @@ retrieve_video_parameters (struct multiboot_info *mbi,
grub_video_driver_id_t driv_id;
struct grub_video_palette_data palette[256];
err = set_video_mode ();
err = grub_multiboot_set_video_mode ();
if (err)
{
grub_print_error ();
@ -283,7 +366,8 @@ grub_multiboot_make_mbi (void *orig, grub_uint32_t dest, grub_off_t buf_off,
mbi->mods_count = 0;
}
mmap_size = grub_get_multiboot_mmap_len ();
mmap_size = grub_get_multiboot_mmap_count ()
* sizeof (struct multiboot_mmap_entry);
grub_fill_multiboot_mmap ((struct multiboot_mmap_entry *) ptrorig);
mbi->mmap_length = mmap_size;
mbi->mmap_addr = ptrdest;
@ -425,7 +509,6 @@ grub_multiboot_add_module (grub_addr_t start, grub_size_t size,
void
grub_multiboot_set_bootdev (void)
{
char *p;
grub_uint32_t biosdev, slice = ~0, part = ~0;
grub_device_t dev;
@ -435,24 +518,19 @@ grub_multiboot_set_bootdev (void)
biosdev = 0xffffffff;
#endif
if (biosdev == 0xffffffff)
return;
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->disk->partition->parent)
{
part = dev->disk->partition->number;
slice = dev->disk->partition->parent->number;
}
else
slice = dev->disk->partition->number;
}
if (dev)
grub_device_close (dev);

View file

@ -31,6 +31,7 @@
#include <grub/machine/memory.h>
#include <grub/dl.h>
#include <grub/command.h>
#include <grub/msdos_partition.h>
#include <grub/machine/biosnum.h>
#include <grub/i18n.h>
#include <grub/video.h>
@ -98,10 +99,22 @@ grub_chainloader_cmd (const char *filename, grub_chainloader_flags_t flags)
dev = grub_device_open (0);
if (dev && dev->disk && dev->disk->partition)
{
grub_disk_read (dev->disk, dev->disk->partition->offset, 446, 64,
(void *) GRUB_MEMORY_MACHINE_PART_TABLE_ADDR);
part_addr = (void *) (GRUB_MEMORY_MACHINE_PART_TABLE_ADDR
+ (dev->disk->partition->index << 4));
grub_disk_t disk = dev->disk;
if (disk)
{
grub_partition_t p = disk->partition;
if (p && grub_strcmp (p->partmap->name, "msdos") == 0)
{
disk->partition = p->parent;
grub_disk_read (disk, p->offset, 446, 64,
(void *) GRUB_MEMORY_MACHINE_PART_TABLE_ADDR);
part_addr = (void *) (GRUB_MEMORY_MACHINE_PART_TABLE_ADDR
+ (p->index << 4));
disk->partition = p;
}
}
}
if (dev)

View file

@ -33,6 +33,7 @@
#include <grub/command.h>
#include <grub/gzio.h>
#include <grub/i18n.h>
#include <grub/bitmap_scale.h>
#define min(a,b) (((a) < (b)) ? (a) : (b))
#define max(a,b) (((a) > (b)) ? (a) : (b))
@ -754,11 +755,13 @@ grub_cpu_xnu_fill_devicetree (void)
#endif
/* The name of key for new table. */
grub_sprintf (guidbuf, "%08x-%04x-%04x-%02x%02x-",
guid.data1, guid.data2, guid.data3, guid.data4[0],
guid.data4[1]);
grub_snprintf (guidbuf, sizeof (guidbuf), "%08x-%04x-%04x-%02x%02x-",
guid.data1, guid.data2, guid.data3, guid.data4[0],
guid.data4[1]);
for (j = 2; j < 8; j++)
grub_sprintf (guidbuf + grub_strlen (guidbuf), "%02x", guid.data4[j]);
grub_snprintf (guidbuf + grub_strlen (guidbuf),
sizeof (guidbuf) - grub_strlen (guidbuf),
"%02x", guid.data4[j]);
/* For some reason GUID has to be in uppercase. */
for (j = 0; guidbuf[j] ; j++)
if (guidbuf[j] >= 'a' && guidbuf[j] <= 'f')
@ -847,9 +850,11 @@ grub_xnu_set_video (struct grub_xnu_boot_params *params)
{
struct grub_video_mode_info mode_info;
int ret;
char *tmp, *modevar;
char *tmp;
const char *modevar;
void *framebuffer;
grub_err_t err;
struct grub_video_bitmap *bitmap = NULL;
modevar = grub_env_get ("gfxpayload");
/* Consider only graphical 32-bit deep modes. */
@ -860,12 +865,9 @@ grub_xnu_set_video (struct grub_xnu_boot_params *params)
32 << GRUB_VIDEO_MODE_TYPE_DEPTH_POS);
else
{
tmp = grub_malloc (grub_strlen (modevar)
+ sizeof (DEFAULT_VIDEO_MODE) + 1);
tmp = grub_xasprintf ("%s;" DEFAULT_VIDEO_MODE, modevar);
if (! tmp)
return grub_error (GRUB_ERR_OUT_OF_MEMORY,
"couldn't allocate temporary storag");
grub_sprintf (tmp, "%s;" DEFAULT_VIDEO_MODE, modevar);
return grub_errno;
err = grub_video_set_mode (tmp,
GRUB_VIDEO_MODE_TYPE_PURE_TEXT
| GRUB_VIDEO_MODE_TYPE_DEPTH_MASK,
@ -876,31 +878,46 @@ grub_xnu_set_video (struct grub_xnu_boot_params *params)
if (err)
return err;
ret = grub_video_get_info (&mode_info);
if (ret)
return grub_error (GRUB_ERR_IO, "couldn't retrieve video parameters");
if (grub_xnu_bitmap)
{
if (grub_xnu_bitmap_mode == GRUB_XNU_BITMAP_STRETCH)
err = grub_video_bitmap_create_scaled (&bitmap,
mode_info.width,
mode_info.height,
grub_xnu_bitmap,
GRUB_VIDEO_BITMAP_SCALE_METHOD_BEST);
else
bitmap = grub_xnu_bitmap;
}
if (bitmap)
{
int x, y;
x = mode_info.width - grub_xnu_bitmap->mode_info.width;
x = mode_info.width - bitmap->mode_info.width;
x /= 2;
y = mode_info.height - grub_xnu_bitmap->mode_info.height;
y = mode_info.height - bitmap->mode_info.height;
y /= 2;
err = grub_video_blit_bitmap (grub_xnu_bitmap,
err = grub_video_blit_bitmap (bitmap,
GRUB_VIDEO_BLIT_REPLACE,
x > 0 ? x : 0,
y > 0 ? y : 0,
x < 0 ? -x : 0,
y < 0 ? -y : 0,
min (grub_xnu_bitmap->mode_info.width,
min (bitmap->mode_info.width,
mode_info.width),
min (grub_xnu_bitmap->mode_info.height,
min (bitmap->mode_info.height,
mode_info.height));
if (err)
{
grub_print_error ();
grub_errno = GRUB_ERR_NONE;
grub_xnu_bitmap = 0;
}
err = GRUB_ERR_NONE;
}
if (err)
{
grub_print_error ();
grub_errno = GRUB_ERR_NONE;
bitmap = 0;
}
ret = grub_video_get_info_and_fini (&mode_info, &framebuffer);
@ -913,8 +930,8 @@ grub_xnu_set_video (struct grub_xnu_boot_params *params)
params->lfb_line_len = mode_info.pitch;
params->lfb_base = PTR_TO_UINT32 (framebuffer);
params->lfb_mode = grub_xnu_bitmap
? GRUB_XNU_VIDEO_SPLASH : GRUB_XNU_VIDEO_TEXT_IN_VIDEO;
params->lfb_mode = bitmap ? GRUB_XNU_VIDEO_SPLASH
: GRUB_XNU_VIDEO_TEXT_IN_VIDEO;
return GRUB_ERR_NONE;
}