Resync with trunk

This commit is contained in:
Robert Millan 2010-01-18 15:02:21 +00:00
commit e68d3b243f
706 changed files with 157184 additions and 45875 deletions

62
loader/aout.c Normal file
View file

@ -0,0 +1,62 @@
/*
* Copyright (C) 2008 Free Software Foundation, Inc.
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <grub/file.h>
#include <grub/err.h>
#include <grub/dl.h>
#include <grub/misc.h>
#include <grub/aout.h>
int
grub_aout_get_type (union grub_aout_header *header)
{
int magic;
magic = AOUT_GETMAGIC (header->aout32);
if ((magic == AOUT32_OMAGIC) || (magic == AOUT32_NMAGIC) ||
(magic == AOUT32_ZMAGIC) || (magic == AOUT32_QMAGIC))
return AOUT_TYPE_AOUT32;
else if ((magic == AOUT64_OMAGIC) || (magic == AOUT64_NMAGIC) ||
(magic == AOUT64_ZMAGIC))
return AOUT_TYPE_AOUT64;
else
return AOUT_TYPE_NONE;
}
grub_err_t
grub_aout_load (grub_file_t file, int offset,
grub_addr_t load_addr,
int load_size,
grub_addr_t bss_end_addr)
{
if ((grub_file_seek (file, offset)) == (grub_off_t) - 1)
return grub_errno;
if (!load_size)
load_size = file->size - offset;
grub_file_read (file, (void *) load_addr, load_size);
if (grub_errno)
return grub_errno;
if (bss_end_addr)
grub_memset ((char *) load_addr + load_size, 0,
bss_end_addr - load_addr - load_size);
return GRUB_ERR_NONE;
}

332
loader/efi/appleloader.c Normal file
View file

@ -0,0 +1,332 @@
/* appleloader.c - apple legacy boot loader. */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 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/>.
*/
#include <grub/loader.h>
#include <grub/err.h>
#include <grub/mm.h>
#include <grub/dl.h>
#include <grub/misc.h>
#include <grub/efi/api.h>
#include <grub/efi/efi.h>
#include <grub/command.h>
#include <grub/i18n.h>
static grub_dl_t my_mod;
static grub_efi_handle_t image_handle;
static grub_efi_char16_t *cmdline;
static grub_err_t
grub_appleloader_unload (void)
{
grub_efi_boot_services_t *b;
b = grub_efi_system_table->boot_services;
efi_call_1 (b->unload_image, image_handle);
grub_free (cmdline);
cmdline = 0;
grub_dl_unref (my_mod);
return GRUB_ERR_NONE;
}
static grub_err_t
grub_appleloader_boot (void)
{
grub_efi_boot_services_t *b;
b = grub_efi_system_table->boot_services;
efi_call_3 (b->start_image, image_handle, 0, 0);
grub_appleloader_unload ();
return grub_errno;
}
struct piwg_full_device_path
{
struct grub_efi_memory_mapped_device_path comp1;
struct grub_efi_piwg_device_path comp2;
struct grub_efi_device_path end;
};
/* early 2006 Core Duo / Core Solo models */
static struct piwg_full_device_path devpath_1 =
{
.comp1 =
{
.header = {
.type = GRUB_EFI_HARDWARE_DEVICE_PATH_TYPE,
.subtype = GRUB_EFI_MEMORY_MAPPED_DEVICE_PATH_SUBTYPE,
.length = {sizeof (struct grub_efi_memory_mapped_device_path), 0}
},
.memory_type = GRUB_EFI_MEMORY_MAPPED_IO,
.start_address = 0xffe00000,
.end_address = 0xfff9ffff
},
.comp2 =
{
.header = {
.type = GRUB_EFI_MEDIA_DEVICE_PATH_TYPE,
.subtype = GRUB_EFI_PIWG_DEVICE_PATH_SUBTYPE,
.length = {sizeof (struct grub_efi_piwg_device_path), 0}
},
.guid = {0x2B0585EB, 0xD8B8, 0x49A9, {0x8B, 0x8C, 0xE2, 0x1B,
0x01, 0xAE, 0xF2, 0xB7}}
},
.end =
{
.type = GRUB_EFI_END_DEVICE_PATH_TYPE,
.subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE,
.length = {sizeof (struct grub_efi_device_path), 0}
}
};
/* mid-2006 Mac Pro (and probably other Core 2 models) */
static struct piwg_full_device_path devpath_2 =
{
.comp1 =
{
.header = {
.type = GRUB_EFI_HARDWARE_DEVICE_PATH_TYPE,
.subtype = GRUB_EFI_MEMORY_MAPPED_DEVICE_PATH_SUBTYPE,
.length = {sizeof (struct grub_efi_memory_mapped_device_path), 0}
},
.memory_type = GRUB_EFI_MEMORY_MAPPED_IO,
.start_address = 0xffe00000,
.end_address = 0xfff7ffff
},
.comp2 =
{
.header = {
.type = GRUB_EFI_MEDIA_DEVICE_PATH_TYPE,
.subtype = GRUB_EFI_PIWG_DEVICE_PATH_SUBTYPE,
.length = {sizeof (struct grub_efi_piwg_device_path), 0}
},
.guid = {0x2B0585EB, 0xD8B8, 0x49A9, {0x8B, 0x8C, 0xE2, 0x1B,
0x01, 0xAE, 0xF2, 0xB7}}
},
.end =
{
.type = GRUB_EFI_END_DEVICE_PATH_TYPE,
.subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE,
.length = {sizeof (struct grub_efi_device_path), 0}
}
};
/* mid-2007 MBP ("Santa Rosa" based models) */
static struct piwg_full_device_path devpath_3 =
{
.comp1 =
{
.header = {
.type = GRUB_EFI_HARDWARE_DEVICE_PATH_TYPE,
.subtype = GRUB_EFI_MEMORY_MAPPED_DEVICE_PATH_SUBTYPE,
.length = {sizeof (struct grub_efi_memory_mapped_device_path), 0}
},
.memory_type = GRUB_EFI_MEMORY_MAPPED_IO,
.start_address = 0xffe00000,
.end_address = 0xfff8ffff
},
.comp2 =
{
.header = {
.type = GRUB_EFI_MEDIA_DEVICE_PATH_TYPE,
.subtype = GRUB_EFI_PIWG_DEVICE_PATH_SUBTYPE,
.length = {sizeof (struct grub_efi_piwg_device_path), 0}
},
.guid = {0x2B0585EB, 0xD8B8, 0x49A9, {0x8B, 0x8C, 0xE2, 0x1B,
0x01, 0xAE, 0xF2, 0xB7}}
},
.end =
{
.type = GRUB_EFI_END_DEVICE_PATH_TYPE,
.subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE,
.length = {sizeof (struct grub_efi_device_path), 0}
}
};
/* early-2008 MBA */
static struct piwg_full_device_path devpath_4 =
{
.comp1 =
{
.header = {
.type = GRUB_EFI_HARDWARE_DEVICE_PATH_TYPE,
.subtype = GRUB_EFI_MEMORY_MAPPED_DEVICE_PATH_SUBTYPE,
.length = {sizeof (struct grub_efi_memory_mapped_device_path), 0}
},
.memory_type = GRUB_EFI_MEMORY_MAPPED_IO,
.start_address = 0xffc00000,
.end_address = 0xfff8ffff
},
.comp2 =
{
.header = {
.type = GRUB_EFI_MEDIA_DEVICE_PATH_TYPE,
.subtype = GRUB_EFI_PIWG_DEVICE_PATH_SUBTYPE,
.length = {sizeof (struct grub_efi_piwg_device_path), 0}
},
.guid = {0x2B0585EB, 0xD8B8, 0x49A9, {0x8B, 0x8C, 0xE2, 0x1B,
0x01, 0xAE, 0xF2, 0xB7}}
},
.end =
{
.type = GRUB_EFI_END_DEVICE_PATH_TYPE,
.subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE,
.length = {sizeof (struct grub_efi_device_path), 0}
}
};
/* late-2008 MB/MBP (NVidia chipset) */
static struct piwg_full_device_path devpath_5 =
{
.comp1 =
{
.header = {
.type = GRUB_EFI_HARDWARE_DEVICE_PATH_TYPE,
.subtype = GRUB_EFI_MEMORY_MAPPED_DEVICE_PATH_SUBTYPE,
.length = {sizeof (struct grub_efi_memory_mapped_device_path), 0}
},
.memory_type = GRUB_EFI_MEMORY_MAPPED_IO,
.start_address = 0xffcb4000,
.end_address = 0xffffbfff
},
.comp2 =
{
.header = {
.type = GRUB_EFI_MEDIA_DEVICE_PATH_TYPE,
.subtype = GRUB_EFI_PIWG_DEVICE_PATH_SUBTYPE,
.length = {sizeof (struct grub_efi_piwg_device_path), 0}
},
.guid = {0x2B0585EB, 0xD8B8, 0x49A9, {0x8B, 0x8C, 0xE2, 0x1B,
0x01, 0xAE, 0xF2, 0xB7}}
},
.end =
{
.type = GRUB_EFI_END_DEVICE_PATH_TYPE,
.subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE,
.length = {sizeof (struct grub_efi_device_path), 0}
}
};
struct devdata
{
char *model;
grub_efi_device_path_t *devpath;
};
struct devdata devs[] =
{
{"Core Duo/Solo", (grub_efi_device_path_t *) &devpath_1},
{"Mac Pro", (grub_efi_device_path_t *) &devpath_2},
{"MBP", (grub_efi_device_path_t *) &devpath_3},
{"MBA", (grub_efi_device_path_t *) &devpath_4},
{"MB NV", (grub_efi_device_path_t *) &devpath_5},
{NULL, NULL},
};
static grub_err_t
grub_cmd_appleloader (grub_command_t cmd __attribute__ ((unused)),
int argc, char *argv[])
{
grub_efi_boot_services_t *b;
grub_efi_loaded_image_t *loaded_image;
struct devdata *pdev;
grub_dl_ref (my_mod);
/* Initialize some global variables. */
image_handle = 0;
b = grub_efi_system_table->boot_services;
for (pdev = devs ; pdev->devpath ; pdev++)
if (efi_call_6 (b->load_image, 0, grub_efi_image_handle, pdev->devpath,
NULL, 0, &image_handle) == GRUB_EFI_SUCCESS)
break;
if (! pdev->devpath)
{
grub_error (GRUB_ERR_BAD_OS, "can't find model");
goto fail;
}
grub_printf ("Model : %s\n", pdev->model);
loaded_image = grub_efi_get_loaded_image (image_handle);
if (! loaded_image)
{
grub_error (GRUB_ERR_BAD_OS, "no loaded image available");
goto fail;
}
if (argc > 0)
{
int i, len;
grub_efi_char16_t *p16;
for (i = 0, len = 0; i < argc; i++)
len += grub_strlen (argv[i]) + 1;
len *= sizeof (grub_efi_char16_t);
cmdline = p16 = grub_malloc (len);
if (! cmdline)
goto fail;
for (i = 0; i < argc; i++)
{
char *p8;
p8 = argv[i];
while (*p8)
*(p16++) = *(p8++);
*(p16++) = ' ';
}
*(--p16) = 0;
loaded_image->load_options = cmdline;
loaded_image->load_options_size = len;
}
grub_loader_set (grub_appleloader_boot, grub_appleloader_unload, 0);
return 0;
fail:
grub_dl_unref (my_mod);
return grub_errno;
}
static grub_command_t cmd;
GRUB_MOD_INIT(appleloader)
{
cmd = grub_register_command ("appleloader", grub_cmd_appleloader,
"[OPTS]", N_("Boot legacy system."));
my_mod = mod;
}
GRUB_MOD_FINI(appleloader)
{
grub_unregister_command (cmd);
}

View file

@ -1,7 +1,7 @@
/* chainloader.c - boot another boot loader */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2002,2004,2006,2007 Free Software Foundation, Inc.
* Copyright (C) 2002,2004,2006,2007,2008 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
@ -25,14 +25,15 @@
#include <grub/device.h>
#include <grub/disk.h>
#include <grub/misc.h>
#include <grub/charset.h>
#include <grub/mm.h>
#include <grub/types.h>
#include <grub/rescue.h>
#include <grub/dl.h>
#include <grub/efi/api.h>
#include <grub/efi/efi.h>
#include <grub/efi/disk.h>
#include <grub/efi/chainloader.h>
#include <grub/command.h>
#include <grub/i18n.h>
static grub_dl_t my_mod;
@ -40,17 +41,21 @@ static grub_efi_physical_address_t address;
static grub_efi_uintn_t pages;
static grub_efi_device_path_t *file_path;
static grub_efi_handle_t image_handle;
static grub_efi_char16_t *cmdline;
static grub_err_t
grub_chainloader_unload (void)
{
grub_efi_boot_services_t *b;
b = grub_efi_system_table->boot_services;
b->unload_image (image_handle);
b->free_pages (address, pages);
efi_call_1 (b->unload_image, image_handle);
efi_call_2 (b->free_pages, address, pages);
grub_free (file_path);
grub_free (cmdline);
cmdline = 0;
grub_dl_unref (my_mod);
return GRUB_ERR_NONE;
}
@ -62,21 +67,21 @@ grub_chainloader_boot (void)
grub_efi_status_t status;
grub_efi_uintn_t exit_data_size;
grub_efi_char16_t *exit_data;
b = grub_efi_system_table->boot_services;
status = b->start_image (image_handle, &exit_data_size, &exit_data);
status = efi_call_3 (b->start_image, image_handle, &exit_data_size, &exit_data);
if (status != GRUB_EFI_SUCCESS)
{
if (exit_data)
{
char *buf;
buf = grub_malloc (exit_data_size * 4 + 1);
if (buf)
{
*grub_utf16_to_utf8 ((grub_uint8_t *) buf,
exit_data, exit_data_size) = 0;
grub_error (GRUB_ERR_BAD_OS, buf);
grub_free (buf);
}
@ -86,10 +91,10 @@ grub_chainloader_boot (void)
}
if (exit_data)
b->free_pool (exit_data);
efi_call_1 (b->free_pool, exit_data);
grub_chainloader_unload ();
return grub_errno;
}
@ -99,7 +104,7 @@ copy_file_path (grub_efi_file_path_device_path_t *fp,
{
grub_efi_char16_t *p;
grub_efi_uint16_t size;
fp->header.type = GRUB_EFI_MEDIA_DEVICE_PATH_TYPE;
fp->header.subtype = GRUB_EFI_FILE_PATH_DEVICE_PATH_SUBTYPE;
size = len * sizeof (grub_efi_char16_t) + sizeof (*fp);
@ -132,7 +137,7 @@ make_file_path (grub_efi_device_path_t *dp, const char *filename)
grub_error (GRUB_ERR_BAD_FILENAME, "invalid EFI file path");
return 0;
}
size = 0;
d = dp;
while (1)
@ -142,7 +147,7 @@ make_file_path (grub_efi_device_path_t *dp, const char *filename)
break;
d = GRUB_EFI_NEXT_DEVICE_PATH (d);
}
file_path = grub_malloc (size
+ ((grub_strlen (dir_start) + 1)
* sizeof (grub_efi_char16_t))
@ -151,7 +156,7 @@ make_file_path (grub_efi_device_path_t *dp, const char *filename)
return 0;
grub_memcpy (file_path, dp, size);
/* Fill the file path for the directory. */
d = (grub_efi_device_path_t *) ((char *) file_path
+ ((char *) d - (char *) dp));
@ -174,8 +179,9 @@ make_file_path (grub_efi_device_path_t *dp, const char *filename)
return file_path;
}
void
grub_chainloader_cmd (const char *filename)
static grub_err_t
grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
int argc, char *argv[])
{
grub_file_t file = 0;
grub_ssize_t size;
@ -185,14 +191,19 @@ grub_chainloader_cmd (const char *filename)
grub_device_t dev = 0;
grub_efi_device_path_t *dp = 0;
grub_efi_loaded_image_t *loaded_image;
char *filename;
if (argc == 0)
return grub_error (GRUB_ERR_BAD_ARGUMENT, "no file specified");
filename = argv[0];
grub_dl_ref (my_mod);
/* Initialize some global variables. */
address = 0;
image_handle = 0;
file_path = 0;
b = grub_efi_system_table->boot_services;
file = grub_file_open (filename);
@ -210,7 +221,7 @@ grub_chainloader_cmd (const char *filename)
if (dev_handle)
dp = grub_efi_get_device_path (dev_handle);
}
if (! dev->disk || ! dev_handle || ! dp)
{
grub_error (GRUB_ERR_BAD_DEVICE, "not a valid root device");
@ -223,11 +234,11 @@ grub_chainloader_cmd (const char *filename)
grub_printf ("file path: ");
grub_efi_print_device_path (file_path);
size = grub_file_size (file);
pages = (((grub_efi_uintn_t) size + ((1 << 12) - 1)) >> 12);
status = b->allocate_pages (GRUB_EFI_ALLOCATE_ANY_PAGES,
status = efi_call_4 (b->allocate_pages, GRUB_EFI_ALLOCATE_ANY_PAGES,
GRUB_EFI_LOADER_CODE,
pages, &address);
if (status != GRUB_EFI_SUCCESS)
@ -244,7 +255,7 @@ grub_chainloader_cmd (const char *filename)
goto fail;
}
status = b->load_image (0, grub_efi_image_handle, file_path,
status = efi_call_6 (b->load_image, 0, grub_efi_image_handle, file_path,
(void *) ((grub_addr_t) address), size,
&image_handle);
if (status != GRUB_EFI_SUCCESS)
@ -253,7 +264,7 @@ grub_chainloader_cmd (const char *filename)
grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of resources");
else
grub_error (GRUB_ERR_BAD_OS, "cannot load image");
goto fail;
}
@ -267,48 +278,70 @@ grub_chainloader_cmd (const char *filename)
goto fail;
}
loaded_image->device_handle = dev_handle;
grub_file_close (file);
if (argc > 1)
{
int i, len;
grub_efi_char16_t *p16;
for (i = 1, len = 0; i < argc; i++)
len += grub_strlen (argv[i]) + 1;
len *= sizeof (grub_efi_char16_t);
cmdline = p16 = grub_malloc (len);
if (! cmdline)
goto fail;
for (i = 1; i < argc; i++)
{
char *p8;
p8 = argv[i];
while (*p8)
*(p16++) = *(p8++);
*(p16++) = ' ';
}
*(--p16) = 0;
loaded_image->load_options = cmdline;
loaded_image->load_options_size = len;
}
grub_loader_set (grub_chainloader_boot, grub_chainloader_unload, 0);
return;
return 0;
fail:
if (dev)
grub_device_close (dev);
if (file)
grub_file_close (file);
if (file_path)
grub_free (file_path);
if (address)
b->free_pages (address, pages);
efi_call_2 (b->free_pages, address, pages);
grub_dl_unref (my_mod);
return grub_errno;
}
static void
grub_rescue_cmd_chainloader (int argc, char *argv[])
{
if (argc == 0)
grub_error (GRUB_ERR_BAD_ARGUMENT, "no file specified");
else
grub_chainloader_cmd (argv[0]);
}
static const char loader_name[] = "chainloader";
static grub_command_t cmd;
GRUB_MOD_INIT(chainloader)
{
grub_rescue_register_command (loader_name,
grub_rescue_cmd_chainloader,
"load another boot loader");
cmd = grub_register_command ("chainloader", grub_cmd_chainloader,
0, N_("Load another boot loader."));
my_mod = mod;
}
GRUB_MOD_FINI(chainloader)
{
grub_rescue_unregister_command (loader_name);
grub_unregister_command (cmd);
}

View file

@ -1,48 +0,0 @@
/* chainloader_normal.c - boot another boot loader */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2004,2006,2007 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/>.
*/
#include <grub/efi/chainloader.h>
#include <grub/err.h>
#include <grub/normal.h>
#include <grub/dl.h>
static grub_err_t
chainloader_command (struct grub_arg_list *state __attribute__ ((unused)),
int argc, char **args)
{
if (argc == 0)
grub_error (GRUB_ERR_BAD_ARGUMENT, "no file specified");
else
grub_chainloader_cmd (args[0]);
return grub_errno;
}
GRUB_MOD_INIT(chainloader_normal)
{
(void) mod; /* To stop warning. */
grub_register_command ("chainloader", chainloader_command,
GRUB_COMMAND_FLAG_BOTH,
"chainloader FILE",
"Prepare to boot another boot loader.", 0);
}
GRUB_MOD_FINI(chainloader_normal)
{
grub_unregister_command ("chainloader");
}

1329
loader/i386/bsd.c Normal file

File diff suppressed because it is too large Load diff

6
loader/i386/bsd32.c Normal file
View file

@ -0,0 +1,6 @@
#define SUFFIX(x) x ## 32
#define GRUB_TARGET_WORDSIZE 32
#define OBJSYM 0
#include <grub/types.h>
typedef grub_uint32_t grub_freebsd_addr_t;
#include "bsdXX.c"

6
loader/i386/bsd64.c Normal file
View file

@ -0,0 +1,6 @@
#define SUFFIX(x) x ## 64
#define GRUB_TARGET_WORDSIZE 64
#define OBJSYM 1
#include <grub/types.h>
typedef grub_uint64_t grub_freebsd_addr_t;
#include "bsdXX.c"

329
loader/i386/bsdXX.c Normal file
View file

@ -0,0 +1,329 @@
#include <grub/loader.h>
#include <grub/cpu/bsd.h>
#include <grub/mm.h>
#include <grub/elf.h>
#include <grub/misc.h>
#include <grub/i386/loader.h>
#define ALIGN_PAGE(a) ALIGN_UP (a, 4096)
static inline grub_err_t
load (grub_file_t file, void *where, grub_off_t off, grub_size_t size)
{
if (PTR_TO_UINT32 (where) + size > grub_os_area_addr + grub_os_area_size)
return grub_error (GRUB_ERR_OUT_OF_RANGE,
"not enough memory for the module");
if (grub_file_seek (file, off) == (grub_off_t) -1)
return grub_errno;
if (grub_file_read (file, where, size)
!= (grub_ssize_t) size)
{
if (grub_errno)
return grub_errno;
else
return grub_error (GRUB_ERR_BAD_OS, "file is truncated");
}
return GRUB_ERR_NONE;
}
static inline grub_err_t
read_headers (grub_file_t file, Elf_Ehdr *e, char **shdr)
{
if (grub_file_seek (file, 0) == (grub_off_t) -1)
return grub_errno;
if (grub_file_read (file, (char *) e, sizeof (*e)) != sizeof (*e))
{
if (grub_errno)
return grub_errno;
else
return grub_error (GRUB_ERR_BAD_OS, "file is too short");
}
if (e->e_ident[EI_MAG0] != ELFMAG0
|| e->e_ident[EI_MAG1] != ELFMAG1
|| e->e_ident[EI_MAG2] != ELFMAG2
|| e->e_ident[EI_MAG3] != ELFMAG3
|| e->e_ident[EI_VERSION] != EV_CURRENT
|| e->e_version != EV_CURRENT)
return grub_error (GRUB_ERR_BAD_OS, "invalid arch independent ELF magic");
if (e->e_ident[EI_CLASS] != SUFFIX (ELFCLASS))
return grub_error (GRUB_ERR_BAD_OS, "invalid arch dependent ELF magic");
*shdr = grub_malloc (e->e_shnum * e->e_shentsize);
if (! *shdr)
return grub_errno;
if (grub_file_seek (file, e->e_shoff) == (grub_off_t) -1)
return grub_errno;
if (grub_file_read (file, *shdr, e->e_shnum * e->e_shentsize)
!= e->e_shnum * e->e_shentsize)
{
if (grub_errno)
return grub_errno;
else
return grub_error (GRUB_ERR_BAD_OS, "file is truncated");
}
return GRUB_ERR_NONE;
}
/* On i386 FreeBSD uses "elf module" approarch for 32-bit variant
and "elf obj module" for 64-bit variant. However it may differ on other
platforms. So I keep both versions. */
#if OBJSYM
grub_err_t
SUFFIX (grub_freebsd_load_elfmodule_obj) (grub_file_t file, int argc,
char *argv[], grub_addr_t *kern_end)
{
Elf_Ehdr e;
Elf_Shdr *s;
char *shdr;
grub_addr_t curload, module;
grub_err_t err;
err = read_headers (file, &e, &shdr);
if (err)
return err;
curload = module = ALIGN_PAGE (*kern_end);
for (s = (Elf_Shdr *) shdr; s < (Elf_Shdr *) ((char *) shdr
+ e.e_shnum * e.e_shentsize);
s = (Elf_Shdr *) ((char *) s + e.e_shentsize))
{
if (s->sh_size == 0)
continue;
if (s->sh_addralign)
curload = ALIGN_UP (curload, s->sh_addralign);
s->sh_addr = curload;
grub_dprintf ("bsd", "loading section to %x, size %d, align %d\n",
(unsigned) curload, (int) s->sh_size,
(int) s->sh_addralign);
switch (s->sh_type)
{
default:
case SHT_PROGBITS:
err = load (file, UINT_TO_PTR (curload), s->sh_offset, s->sh_size);
if (err)
return err;
break;
case SHT_NOBITS:
if (curload + s->sh_size > grub_os_area_addr + grub_os_area_size)
return grub_error (GRUB_ERR_OUT_OF_RANGE,
"not enough memory for the module");
grub_memset (UINT_TO_PTR (curload), 0, s->sh_size);
break;
}
curload += s->sh_size;
}
*kern_end = ALIGN_PAGE (curload);
err = grub_freebsd_add_meta_module (argv[0], FREEBSD_MODTYPE_ELF_MODULE_OBJ,
argc - 1, argv + 1, module,
curload - module);
if (! err)
err = grub_freebsd_add_meta (FREEBSD_MODINFO_METADATA
| FREEBSD_MODINFOMD_ELFHDR,
&e, sizeof (e));
if (! err)
err = grub_freebsd_add_meta (FREEBSD_MODINFO_METADATA
| FREEBSD_MODINFOMD_SHDR,
shdr, e.e_shnum * e.e_shentsize);
return err;
}
#else
grub_err_t
SUFFIX (grub_freebsd_load_elfmodule) (grub_file_t file, int argc, char *argv[],
grub_addr_t *kern_end)
{
Elf_Ehdr e;
Elf_Shdr *s;
char *shdr;
grub_addr_t curload, module;
grub_err_t err;
err = read_headers (file, &e, &shdr);
if (err)
return err;
curload = module = ALIGN_PAGE (*kern_end);
for (s = (Elf_Shdr *) shdr; s < (Elf_Shdr *) ((char *) shdr
+ e.e_shnum * e.e_shentsize);
s = (Elf_Shdr *) ((char *) s + e.e_shentsize))
{
if (s->sh_size == 0)
continue;
if (! (s->sh_flags & SHF_ALLOC))
continue;
grub_dprintf ("bsd", "loading section to %x, size %d, align %d\n",
(unsigned) curload, (int) s->sh_size,
(int) s->sh_addralign);
switch (s->sh_type)
{
default:
case SHT_PROGBITS:
err = load (file, UINT_TO_PTR (module + s->sh_addr),
s->sh_offset, s->sh_size);
if (err)
return err;
break;
case SHT_NOBITS:
if (module + s->sh_addr + s->sh_size
> grub_os_area_addr + grub_os_area_size)
return grub_error (GRUB_ERR_OUT_OF_RANGE,
"not enough memory for the module");
grub_memset (UINT_TO_PTR (module + s->sh_addr), 0, s->sh_size);
break;
}
if (curload < module + s->sh_addr + s->sh_size)
curload = module + s->sh_addr + s->sh_size;
}
load (file, UINT_TO_PTR (module), 0, sizeof (e));
if (curload < module + sizeof (e))
curload = module + sizeof (e);
load (file, UINT_TO_PTR (curload), e.e_shoff,
e.e_shnum * e.e_shentsize);
e.e_shoff = curload - module;
curload += e.e_shnum * e.e_shentsize;
load (file, UINT_TO_PTR (curload), e.e_phoff,
e.e_phnum * e.e_phentsize);
e.e_phoff = curload - module;
curload += e.e_phnum * e.e_phentsize;
*kern_end = curload;
grub_freebsd_add_meta_module (argv[0], FREEBSD_MODTYPE_ELF_MODULE,
argc - 1, argv + 1, module,
curload - module);
return SUFFIX (grub_freebsd_load_elf_meta) (file, kern_end);
}
#endif
grub_err_t
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;
unsigned symoff, stroff, symsize, strsize;
grub_addr_t curload;
grub_freebsd_addr_t symstart, symend, symentsize, dynamic;
Elf_Sym *sym;
const char *str;
unsigned i;
err = read_headers (file, &e, &shdr);
if (err)
return err;
err = grub_freebsd_add_meta (FREEBSD_MODINFO_METADATA |
FREEBSD_MODINFOMD_ELFHDR, &e,
sizeof (e));
if (err)
return err;
for (s = (Elf_Shdr *) shdr; s < (Elf_Shdr *) (shdr
+ e.e_shnum * e.e_shentsize);
s = (Elf_Shdr *) ((char *) s + e.e_shentsize))
if (s->sh_type == SHT_SYMTAB)
break;
if (s >= (Elf_Shdr *) ((char *) shdr
+ e.e_shnum * e.e_shentsize))
return grub_error (GRUB_ERR_BAD_OS, "no symbol table");
symoff = s->sh_offset;
symsize = s->sh_size;
symentsize = s->sh_entsize;
s = (Elf_Shdr *) (shdr + e.e_shentsize * s->sh_link);
stroff = s->sh_offset;
strsize = s->sh_size;
if (*kern_end + 4 * sizeof (grub_freebsd_addr_t) + symsize + strsize
> grub_os_area_addr + grub_os_area_size)
return grub_error (GRUB_ERR_OUT_OF_RANGE,
"not enough memory for kernel symbols");
symstart = curload = ALIGN_UP (*kern_end, sizeof (grub_freebsd_addr_t));
*((grub_freebsd_addr_t *) UINT_TO_PTR (curload)) = symsize;
curload += sizeof (grub_freebsd_addr_t);
if (grub_file_seek (file, symoff) == (grub_off_t) -1)
return grub_errno;
sym = (Elf_Sym *) UINT_TO_PTR (curload);
if (grub_file_read (file, UINT_TO_PTR (curload), symsize) !=
(grub_ssize_t) symsize)
{
if (! grub_errno)
return grub_error (GRUB_ERR_BAD_OS, "invalid ELF");
return grub_errno;
}
curload += symsize;
*((grub_freebsd_addr_t *) UINT_TO_PTR (curload)) = strsize;
curload += sizeof (grub_freebsd_addr_t);
if (grub_file_seek (file, stroff) == (grub_off_t) -1)
return grub_errno;
str = (char *) UINT_TO_PTR (curload);
if (grub_file_read (file, UINT_TO_PTR (curload), strsize)
!= (grub_ssize_t) strsize)
{
if (! grub_errno)
return grub_error (GRUB_ERR_BAD_OS, "invalid ELF");
return grub_errno;
}
curload += strsize;
curload = ALIGN_UP (curload, sizeof (grub_freebsd_addr_t));
symend = curload;
for (i = 0;
i * symentsize < symsize;
i++, sym = (Elf_Sym *) ((char *) sym + symentsize))
{
const char *name = str + sym->st_name;
if (grub_strcmp (name, "_DYNAMIC") == 0)
break;
}
if (i * symentsize < symsize)
{
dynamic = sym->st_value;
grub_dprintf ("bsd", "dynamic = %llx\n", (unsigned long long) dynamic);
err = grub_freebsd_add_meta (FREEBSD_MODINFO_METADATA |
FREEBSD_MODINFOMD_DYNAMIC, &dynamic,
sizeof (dynamic));
if (err)
return err;
}
err = grub_freebsd_add_meta (FREEBSD_MODINFO_METADATA |
FREEBSD_MODINFOMD_SSYM, &symstart,
sizeof (symstart));
if (err)
return err;
err = grub_freebsd_add_meta (FREEBSD_MODINFO_METADATA |
FREEBSD_MODINFOMD_ESYM, &symend,
sizeof (symend));
if (err)
return err;
*kern_end = ALIGN_PAGE (curload);
return GRUB_ERR_NONE;
}

45
loader/i386/bsd_helper.S Normal file
View file

@ -0,0 +1,45 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 1999,2000,2001,2002,2003,2005,2006,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/>.
*/
#include <grub/symbol.h>
.p2align 2
.code32
/*
* Use cdecl calling convention for *BSD kernels.
*/
FUNCTION(grub_unix_real_boot)
/* Interrupts should be disabled. */
cli
/* Discard `grub_unix_real_boot' return address. */
popl %eax
/* Fetch `entry' address ... */
popl %eax
/*
* ... and put our return address in its place. The kernel will
* ignore it, but it expects %esp to point to it.
*/
call *%eax

View file

@ -0,0 +1,88 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
* Copyright (C) 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/>.
*/
/* Based on the code from FreeBSD originally distributed under the
following terms: */
/*-
* Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
static void
fill_bsd64_pagetable (grub_uint8_t *target)
{
grub_uint64_t *pt2, *pt3, *pt4;
int i;
#define PG_V 0x001
#define PG_RW 0x002
#define PG_U 0x004
#define PG_PS 0x080
pt4 = (grub_uint64_t *) target;
pt3 = (grub_uint64_t *) (target + 4096);
pt2 = (grub_uint64_t *) (target + 8192);
grub_memset ((char *) target, 0, 4096 * 3);
/*
* This is kinda brutal, but every single 1GB VM memory segment points to
* the same first 1GB of physical memory. But it is how BSD expects
* it to be.
*/
for (i = 0; i < 512; i++)
{
/* Each slot of the level 4 pages points to the same level 3 page */
pt4[i] = (grub_addr_t) &pt3[0];
pt4[i] |= PG_V | PG_RW | PG_U;
/* Each slot of the level 3 pages points to the same level 2 page */
pt3[i] = (grub_addr_t) &pt2[0];
pt3[i] |= PG_V | PG_RW | PG_U;
/* The level 2 page slots are mapped with 2MB pages for 1GB. */
pt2[i] = i * (2 * 1024 * 1024);
pt2[i] |= PG_V | PG_RW | PG_PS | PG_U;
}
}

View file

@ -0,0 +1,124 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (c) 2003 Peter Wemm <peter@FreeBSD.org>
* Copyright (C) 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/>.
*/
/* Based on the code from FreeBSD originally distributed under the
following terms: */
/*-
* Copyright (c) 2003 Peter Wemm <peter@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#define MSR_EFER 0xc0000080
#define EFER_LME 0x00000100
#define CR4_PAE 0x00000020
#define CR4_PSE 0x00000010
#define CR0_PG 0x80000000
#include <grub/symbol.h>
.p2align 2
.code32
VARIABLE(grub_bsd64_trampoline_start)
/* Discard `grub_unix_real_boot' return address. */
popl %eax
/* entry */
popl %edi
/* entry_hi */
popl %esi
cli
/* Turn on EFER.LME. */
movl $MSR_EFER, %ecx
rdmsr
orl $EFER_LME, %eax
wrmsr
/* Turn on PAE. */
movl %cr4, %eax
orl $(CR4_PAE | CR4_PSE), %eax
movl %eax, %cr4
/* Set %cr3 for PT4. */
popl %eax
movl %eax, %cr3
/* Push a dummy return address. */
pushl %eax
/* Turn on paging (implicitly sets EFER.LMA). */
movl %cr0, %eax
orl $CR0_PG, %eax
movl %eax, %cr0
/* Now we're in compatibility mode. set %cs for long mode. */
/* lgdt */
.byte 0x0f
.byte 0x01
.byte 0x15
VARIABLE (grub_bsd64_trampoline_gdt)
.long 0x0
/* ljmp */
.byte 0xea
VARIABLE (grub_bsd64_trampoline_selfjump)
.long 0x0
.word 0x08
.code64
bsd64_longmode:
/* We're still running V=P, jump to entry point. */
movl %esi, %eax
salq $32, %rax
orq %rdi, %rax
pushq %rax
ret
VARIABLE(grub_bsd64_trampoline_end)

View file

@ -1,6 +1,6 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2006,2007 Free Software Foundation, Inc.
* Copyright (C) 2006,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
@ -23,13 +23,20 @@
#include <grub/err.h>
#include <grub/misc.h>
#include <grub/types.h>
#include <grub/rescue.h>
#include <grub/dl.h>
#include <grub/mm.h>
#include <grub/term.h>
#include <grub/cpu/linux.h>
#include <grub/efi/api.h>
#include <grub/efi/efi.h>
#include <grub/efi/uga_draw.h>
#include <grub/pci.h>
#include <grub/command.h>
#include <grub/memory.h>
#include <grub/i18n.h>
#define GRUB_LINUX_CL_OFFSET 0x1000
#define GRUB_LINUX_CL_END_OFFSET 0x2000
#define NEXT_MEMORY_DESCRIPTOR(desc, size) \
((grub_efi_memory_descriptor_t *) ((char *) (desc) + (size)))
@ -60,28 +67,24 @@ static grub_uint8_t gdt[] __attribute__ ((aligned(16))) =
struct gdt_descriptor
{
grub_uint16_t dummy;
grub_uint16_t limit;
grub_uint32_t base;
} __attribute__ ((aligned(4), packed));
void *base;
} __attribute__ ((packed));
static struct gdt_descriptor gdt_desc =
{
0,
sizeof (gdt) - 1,
(grub_addr_t) gdt
gdt
};
struct idt_descriptor
{
grub_uint16_t dummy;
grub_uint16_t limit;
grub_uint32_t base;
} __attribute__ ((aligned(4)));
void *base;
} __attribute__ ((packed));
static struct idt_descriptor idt_desc =
{
0,
0,
0
};
@ -101,21 +104,21 @@ find_mmap_size (void)
if (mmap_size != 0)
return mmap_size;
mmap_size = (1 << 12);
while (1)
{
int ret;
grub_efi_memory_descriptor_t *mmap;
grub_efi_uintn_t desc_size;
mmap = grub_malloc (mmap_size);
if (! mmap)
return 0;
ret = grub_efi_get_memory_map (&mmap_size, mmap, 0, &desc_size, 0);
grub_free (mmap);
if (ret < 0)
grub_fatal ("cannot get memory map");
else if (ret > 0)
@ -145,7 +148,7 @@ free_pages (void)
grub_efi_free_pages ((grub_addr_t) prot_mode_mem, prot_mode_pages);
prot_mode_mem = 0;
}
if (initrd_mem)
{
grub_efi_free_pages ((grub_addr_t) initrd_mem, initrd_pages);
@ -156,30 +159,31 @@ free_pages (void)
/* Allocate pages for the real mode code and the protected mode code
for linux as well as a memory map buffer. */
static int
allocate_pages (grub_size_t real_size, grub_size_t prot_size)
allocate_pages (grub_size_t prot_size)
{
grub_efi_uintn_t desc_size;
grub_efi_memory_descriptor_t *mmap, *mmap_end;
grub_efi_uintn_t mmap_size, tmp_mmap_size;
grub_efi_memory_descriptor_t *desc;
grub_size_t real_size;
/* Make sure that each size is aligned to a page boundary. */
real_size = page_align (real_size + GRUB_DISK_SECTOR_SIZE);
real_size = GRUB_LINUX_CL_END_OFFSET;
prot_size = page_align (prot_size);
mmap_size = find_mmap_size ();
grub_dprintf ("linux", "real_size = %x, prot_size = %x, mmap_size = %x\n",
real_size, prot_size, mmap_size);
(unsigned) real_size, (unsigned) prot_size, (unsigned) mmap_size);
/* Calculate the number of pages; Combine the real mode code with
the memory map buffer for simplicity. */
real_mode_pages = ((real_size + mmap_size) >> 12);
prot_mode_pages = (prot_size >> 12);
/* Initialize the memory pointers with NULL for convenience. */
real_mode_mem = 0;
prot_mode_mem = 0;
/* Read the memory map temporarily, to find free space. */
mmap = grub_malloc (mmap_size);
if (! mmap)
@ -190,7 +194,7 @@ allocate_pages (grub_size_t real_size, grub_size_t prot_size)
grub_fatal ("cannot get memory map");
mmap_end = NEXT_MEMORY_DESCRIPTOR (mmap, tmp_mmap_size);
/* First, find free pages for the real mode code
and the memory map buffer. */
for (desc = mmap;
@ -205,7 +209,7 @@ allocate_pages (grub_size_t real_size, grub_size_t prot_size)
{
grub_efi_physical_address_t physical_end;
grub_efi_physical_address_t addr;
physical_end = desc->physical_start + (desc->num_pages << 12);
if (physical_end > 0x90000)
physical_end = 0x90000;
@ -217,12 +221,12 @@ allocate_pages (grub_size_t real_size, grub_size_t prot_size)
if (addr < 0x10000)
continue;
grub_dprintf ("linux", "trying to allocate %u pages at %x\n",
real_mode_pages, (unsigned) addr);
grub_dprintf ("linux", "trying to allocate %u pages at %lx\n",
(unsigned) real_mode_pages, (unsigned long) addr);
real_mode_mem = grub_efi_allocate_pages (addr, real_mode_pages);
if (! real_mode_mem)
grub_fatal ("cannot allocate pages");
desc->num_pages -= real_mode_pages;
break;
}
@ -235,10 +239,10 @@ allocate_pages (grub_size_t real_size, grub_size_t prot_size)
}
mmap_buf = (void *) ((char *) real_mode_mem + real_size);
/* Next, find free pages for the protected mode code. */
/* XXX what happens if anything is using this address? */
prot_mode_mem = grub_efi_allocate_pages (0x100000, prot_mode_pages);
prot_mode_mem = grub_efi_allocate_pages (0x100000, prot_mode_pages + 1);
if (! prot_mode_mem)
{
grub_error (GRUB_ERR_OUT_OF_MEMORY,
@ -246,6 +250,11 @@ allocate_pages (grub_size_t real_size, grub_size_t prot_size)
goto fail;
}
grub_dprintf ("linux", "real_mode_mem = %lx, real_mode_pages = %x, "
"prot_mode_mem = %lx, prot_mode_pages = %x\n",
(unsigned long) real_mode_mem, (unsigned) real_mode_pages,
(unsigned long) prot_mode_mem, (unsigned) prot_mode_pages);
grub_free (mmap);
return 1;
@ -255,56 +264,154 @@ allocate_pages (grub_size_t real_size, grub_size_t prot_size)
return 0;
}
static void
grub_e820_add_region (struct grub_e820_mmap *e820_map, int *e820_num,
grub_uint64_t start, grub_uint64_t size,
grub_uint32_t type)
{
int n = *e820_num;
if (n >= GRUB_E820_MAX_ENTRY)
grub_fatal ("Too many e820 memory map entries");
if ((n > 0) && (e820_map[n - 1].addr + e820_map[n - 1].size == start) &&
(e820_map[n - 1].type == type))
e820_map[n - 1].size += size;
else
{
e820_map[n].addr = start;
e820_map[n].size = size;
e820_map[n].type = type;
(*e820_num)++;
}
}
#ifdef __x86_64__
extern grub_uint8_t grub_linux_trampoline_start[];
extern grub_uint8_t grub_linux_trampoline_end[];
#endif
static grub_err_t
grub_linux_boot (void)
{
struct linux_kernel_header *lh;
struct linux_kernel_params *params;
grub_efi_uintn_t mmap_size;
grub_efi_uintn_t map_key;
grub_efi_uintn_t desc_size;
grub_efi_uint32_t desc_version;
lh = real_mode_mem;
int e820_num;
params = real_mode_mem;
grub_dprintf ("linux", "code32_start = %x, idt_desc = %x, gdt_desc = %x\n",
(unsigned) lh->code32_start, (grub_addr_t) &(idt_desc.limit),
(grub_addr_t) &(gdt_desc.limit));
grub_dprintf ("linux", "idt = %x:%x, gdt = %x:%x\n",
(unsigned) idt_desc.limit, (unsigned) idt_desc.base,
(unsigned) gdt_desc.limit, (unsigned) gdt_desc.base);
grub_dprintf ("linux", "code32_start = %x, idt_desc = %lx, gdt_desc = %lx\n",
(unsigned) params->code32_start,
(unsigned long) &(idt_desc.limit),
(unsigned long) &(gdt_desc.limit));
grub_dprintf ("linux", "idt = %x:%lx, gdt = %x:%lx\n",
(unsigned) idt_desc.limit, (unsigned long) idt_desc.base,
(unsigned) gdt_desc.limit, (unsigned long) gdt_desc.base);
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)
{
switch (type)
{
case GRUB_MACHINE_MEMORY_AVAILABLE:
grub_e820_add_region (params->e820_map, &e820_num,
addr, size, GRUB_E820_RAM);
break;
#ifdef GRUB_MACHINE_MEMORY_ACPI
case GRUB_MACHINE_MEMORY_ACPI:
grub_e820_add_region (params->e820_map, &e820_num,
addr, size, GRUB_E820_ACPI);
break;
#endif
#ifdef GRUB_MACHINE_MEMORY_NVS
case GRUB_MACHINE_MEMORY_NVS:
grub_e820_add_region (params->e820_map, &e820_num,
addr, size, GRUB_E820_NVS);
break;
#endif
#ifdef GRUB_MACHINE_MEMORY_CODE
case GRUB_MACHINE_MEMORY_CODE:
grub_e820_add_region (params->e820_map, &e820_num,
addr, size, GRUB_E820_EXEC_CODE);
break;
#endif
default:
grub_e820_add_region (params->e820_map, &e820_num,
addr, size, GRUB_E820_RESERVED);
}
return 0;
}
e820_num = 0;
grub_mmap_iterate (hook);
params->mmap_size = e820_num;
mmap_size = find_mmap_size ();
if (grub_efi_get_memory_map (&mmap_size, mmap_buf, &map_key,
&desc_size, &desc_version) <= 0)
grub_fatal ("cannot get memory map");
if (! grub_efi_exit_boot_services (map_key))
grub_fatal ("cannot exit boot services");
grub_fatal ("cannot exit boot services");
/* Note that no boot services are available from here. */
/* Pass EFI parameters. */
if (grub_le_to_cpu16 (params->version) >= 0x0206)
{
params->v0206.efi_mem_desc_size = desc_size;
params->v0206.efi_mem_desc_version = desc_version;
params->v0206.efi_mmap = (grub_uint32_t) (unsigned long) mmap_buf;
params->v0206.efi_mmap_size = mmap_size;
#ifdef __x86_64__
params->v0206.efi_mmap_hi = (grub_uint32_t) ((grub_uint64_t) mmap_buf >> 32);
#endif
}
else if (grub_le_to_cpu16 (params->version) >= 0x0204)
{
params->v0204.efi_mem_desc_size = desc_size;
params->v0204.efi_mem_desc_version = desc_version;
params->v0204.efi_mmap = (grub_uint32_t) (unsigned long) mmap_buf;
params->v0204.efi_mmap_size = mmap_size;
}
#ifdef __x86_64__
grub_memcpy ((char *) prot_mode_mem + (prot_mode_pages << 12),
grub_linux_trampoline_start,
grub_linux_trampoline_end - grub_linux_trampoline_start);
((void (*) (unsigned long, void *)) ((char *) prot_mode_mem
+ (prot_mode_pages << 12)))
(params->code32_start, real_mode_mem);
#else
/* Hardware interrupts are not safe any longer. */
asm volatile ("cli" : : );
/* Pass EFI parameters. */
params->efi_mem_desc_size = desc_size;
params->efi_mem_desc_version = desc_version;
params->efi_mmap = (grub_addr_t) mmap_buf;
params->efi_mmap_size = mmap_size;
/* Pass parameters. */
asm volatile ("movl %0, %%esi" : : "m" (real_mode_mem));
asm volatile ("movl %0, %%ecx" : : "m" (lh->code32_start));
asm volatile ("xorl %%ebx, %%ebx" : : );
/* Load the IDT and the GDT for the bootstrap. */
asm volatile ("lidt %0" : : "m" (idt_desc.limit));
asm volatile ("lgdt %0" : : "m" (gdt_desc.limit));
asm volatile ("lidt %0" : : "m" (idt_desc));
asm volatile ("lgdt %0" : : "m" (gdt_desc));
/* Pass parameters. */
asm volatile ("movl %0, %%ecx" : : "m" (params->code32_start));
asm volatile ("movl %0, %%esi" : : "m" (real_mode_mem));
asm volatile ("xorl %%ebx, %%ebx" : : );
/* Enter Linux. */
asm volatile ("jmp *%%ecx" : : );
#endif
/* Never reach here. */
return GRUB_ERR_NONE;
}
@ -318,8 +425,177 @@ grub_linux_unload (void)
return GRUB_ERR_NONE;
}
void
grub_rescue_cmd_linux (int argc, char *argv[])
static grub_efi_guid_t uga_draw_guid = GRUB_EFI_UGA_DRAW_GUID;
#define RGB_MASK 0xffffff
#define RGB_MAGIC 0x121314
#define LINE_MIN 800
#define LINE_MAX 4096
#define FBTEST_STEP (0x10000 >> 2)
#define FBTEST_COUNT 8
static int
find_line_len (grub_uint32_t *fb_base, grub_uint32_t *line_len)
{
grub_uint32_t *base = (grub_uint32_t *) (grub_target_addr_t) *fb_base;
int i;
for (i = 0; i < FBTEST_COUNT; i++, base += FBTEST_STEP)
{
if ((*base & RGB_MASK) == RGB_MAGIC)
{
int j;
for (j = LINE_MIN; j <= LINE_MAX; j++)
{
if ((base[j] & RGB_MASK) == RGB_MAGIC)
{
*fb_base = (grub_uint32_t) (grub_target_addr_t) base;
*line_len = j << 2;
return 1;
}
}
break;
}
}
return 0;
}
static int
find_framebuf (grub_uint32_t *fb_base, grub_uint32_t *line_len)
{
int found = 0;
auto int NESTED_FUNC_ATTR find_card (grub_pci_device_t dev,
grub_pci_id_t pciid);
int NESTED_FUNC_ATTR find_card (grub_pci_device_t dev,
grub_pci_id_t pciid)
{
grub_pci_address_t addr;
addr = grub_pci_make_address (dev, 2);
if (grub_pci_read (addr) >> 24 == 0x3)
{
int i;
grub_printf ("Display controller: %d:%d.%d\nDevice id: %x\n",
grub_pci_get_bus (dev), grub_pci_get_device (dev),
grub_pci_get_function (dev), pciid);
addr += 8;
for (i = 0; i < 6; i++, addr += 4)
{
grub_uint32_t old_bar1, old_bar2, type;
grub_uint64_t base64;
old_bar1 = grub_pci_read (addr);
if ((! old_bar1) || (old_bar1 & GRUB_PCI_ADDR_SPACE_IO))
continue;
type = old_bar1 & GRUB_PCI_ADDR_MEM_TYPE_MASK;
if (type == GRUB_PCI_ADDR_MEM_TYPE_64)
{
if (i == 5)
break;
old_bar2 = grub_pci_read (addr + 4);
}
else
old_bar2 = 0;
base64 = old_bar2;
base64 <<= 32;
base64 |= (old_bar1 & GRUB_PCI_ADDR_MEM_MASK);
grub_printf ("%s(%d): 0x%llx\n",
((old_bar1 & GRUB_PCI_ADDR_MEM_PREFETCH) ?
"VMEM" : "MMIO"), i,
(unsigned long long) base64);
if ((old_bar1 & GRUB_PCI_ADDR_MEM_PREFETCH) && (! found))
{
*fb_base = base64;
if (find_line_len (fb_base, line_len))
found++;
}
if (type == GRUB_PCI_ADDR_MEM_TYPE_64)
{
i++;
addr += 4;
}
}
}
return found;
}
grub_pci_iterate (find_card);
return found;
}
static int
grub_linux_setup_video (struct linux_kernel_params *params)
{
grub_efi_uga_draw_protocol_t *c;
grub_uint32_t width, height, depth, rate, pixel, fb_base, line_len;
int ret;
c = grub_efi_locate_protocol (&uga_draw_guid, 0);
if (! c)
return 1;
if (efi_call_5 (c->get_mode, c, &width, &height, &depth, &rate))
return 1;
grub_printf ("Video mode: %ux%u-%u@%u\n", width, height, depth, rate);
grub_efi_set_text_mode (0);
pixel = RGB_MAGIC;
efi_call_10 (c->blt, c, (struct grub_efi_uga_pixel *) &pixel,
GRUB_EFI_UGA_VIDEO_FILL, 0, 0, 0, 0, 1, height, 0);
ret = find_framebuf (&fb_base, &line_len);
grub_efi_set_text_mode (1);
if (! ret)
{
grub_printf ("Can\'t find frame buffer address\n");
return 1;
}
grub_printf ("Frame buffer base: 0x%x\n", fb_base);
grub_printf ("Video line length: %d\n", line_len);
params->lfb_width = width;
params->lfb_height = height;
params->lfb_depth = depth;
params->lfb_line_len = line_len;
params->lfb_base = fb_base;
params->lfb_size = (line_len * params->lfb_height + 65535) >> 16;
params->red_mask_size = 8;
params->red_field_pos = 16;
params->green_mask_size = 8;
params->green_field_pos = 8;
params->blue_mask_size = 8;
params->blue_field_pos = 0;
params->reserved_mask_size = 8;
params->reserved_field_pos = 24;
params->have_vga = GRUB_VIDEO_LINUX_TYPE_VESA;
params->vid_mode = 0x338; /* 1024x768x32 */
return 0;
}
static grub_err_t
grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
int argc, char *argv[])
{
grub_file_t file = 0;
struct linux_kernel_header lh;
@ -331,7 +607,7 @@ grub_rescue_cmd_linux (int argc, char *argv[])
char *dest;
grub_dl_ref (my_mod);
if (argc == 0)
{
grub_error (GRUB_ERR_BAD_ARGUMENT, "no kernel specified");
@ -342,9 +618,9 @@ grub_rescue_cmd_linux (int argc, char *argv[])
if (! file)
goto fail;
if (grub_file_read (file, (char *) &lh, sizeof (lh)) != sizeof (lh))
if (grub_file_read (file, &lh, sizeof (lh)) != sizeof (lh))
{
grub_error (GRUB_ERR_READ_ERROR, "cannot read the linux header");
grub_error (GRUB_ERR_READ_ERROR, "cannot read the Linux header");
goto fail;
}
@ -376,44 +652,94 @@ grub_rescue_cmd_linux (int argc, char *argv[])
}
setup_sects = lh.setup_sects;
/* If SETUP_SECTS is not set, set it to the default (4). */
if (! setup_sects)
setup_sects = GRUB_LINUX_DEFAULT_SETUP_SECTS;
real_size = setup_sects << GRUB_DISK_SECTOR_BITS;
prot_size = grub_file_size (file) - real_size - GRUB_DISK_SECTOR_SIZE;
if (! allocate_pages (real_size, prot_size))
if (! allocate_pages (prot_size))
goto fail;
params = (struct linux_kernel_params *) real_mode_mem;
grub_memset (params, 0, GRUB_LINUX_CL_END_OFFSET);
grub_memcpy (&params->setup_sects, &lh.setup_sects, sizeof (lh) - 0x1F1);
params->ps_mouse = params->padding10 = 0;
len = 0x400 - sizeof (lh);
if (grub_file_read (file, (char *) real_mode_mem + sizeof (lh), len) != len)
{
grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file");
goto fail;
}
/* XXX Linux assumes that only elilo can boot Linux on EFI!!! */
lh.type_of_loader = 0x50;
params->type_of_loader = (LINUX_LOADER_ID_ELILO << 4);
lh.cl_magic = GRUB_LINUX_CL_MAGIC;
lh.cl_offset = GRUB_LINUX_CL_END_OFFSET;
lh.cmd_line_ptr = (char *) real_mode_mem + GRUB_LINUX_CL_OFFSET;
lh.ramdisk_image = 0;
lh.ramdisk_size = 0;
params->cl_magic = GRUB_LINUX_CL_MAGIC;
params->cl_offset = 0x1000;
params->cmd_line_ptr = (unsigned long) real_mode_mem + 0x1000;
params->ramdisk_image = 0;
params->ramdisk_size = 0;
params = (struct linux_kernel_params *) &lh;
params->heap_end_ptr = GRUB_LINUX_HEAP_END_OFFSET;
params->loadflags |= GRUB_LINUX_FLAG_CAN_USE_HEAP;
/* These are not needed to be precise, because Linux uses these values
only to raise an error when the decompression code cannot find good
space. */
params->ext_mem = ((32 * 0x100000) >> 10);
params->alt_mem = ((32 * 0x100000) >> 10);
params->video_cursor_x = grub_efi_system_table->con_out->mode->cursor_column;
params->video_cursor_y = grub_efi_system_table->con_out->mode->cursor_row;
{
grub_term_output_t term;
int found = 0;
FOR_ACTIVE_TERM_OUTPUTS(term)
if (grub_strcmp (term->name, "vga_text") == 0
|| grub_strcmp (term->name, "console") == 0)
{
grub_uint16_t pos = grub_term_getxy (term);
params->video_cursor_x = pos >> 8;
params->video_cursor_y = pos & 0xff;
params->video_width = grub_term_width (term);
params->video_height = grub_term_height (term);
found = 1;
break;
}
if (!found)
{
params->video_cursor_x = 0;
params->video_cursor_y = 0;
params->video_width = 80;
params->video_height = 25;
}
}
params->video_page = 0; /* ??? */
params->video_mode = grub_efi_system_table->con_out->mode->mode;
params->video_width = (grub_getwh () >> 8);
params->video_ega_bx = 0;
params->video_height = (grub_getwh () & 0xff);
params->have_vga = 0;
params->font_size = 16; /* XXX */
if (grub_le_to_cpu16 (params->version) >= 0x0206)
{
params->v0206.efi_signature = GRUB_LINUX_EFI_SIGNATURE;
params->v0206.efi_system_table = (grub_uint32_t) (unsigned long) grub_efi_system_table;
#ifdef __x86_64__
params->v0206.efi_system_table_hi = (grub_uint32_t) ((grub_uint64_t) grub_efi_system_table >> 32);
#endif
}
else if (grub_le_to_cpu16 (params->version) >= 0x0204)
{
params->v0204.efi_signature = GRUB_LINUX_EFI_SIGNATURE_0204;
params->v0204.efi_system_table = (grub_uint32_t) (unsigned long) grub_efi_system_table;
}
#if 0
/* The structure is zeroed already. */
/* No VBE on EFI. */
params->lfb_width = 0;
params->lfb_height = 0;
@ -457,10 +783,6 @@ grub_rescue_cmd_linux (int argc, char *argv[])
/* No MCA on EFI. */
params->rom_config_len = 0;
params->efi_signature = GRUB_LINUX_EFI_SIGNATURE; /* XXX not used */
params->efi_system_table = (grub_addr_t) grub_efi_system_table;
/* The other EFI parameters are filled when booting. */
/* No need to fake the BIOS's memory map. */
params->mmap_size = 0;
@ -477,20 +799,18 @@ grub_rescue_cmd_linux (int argc, char *argv[])
grub_memset (params->padding7, 0, sizeof (params->padding7));
grub_memset (params->padding8, 0, sizeof (params->padding8));
grub_memset (params->padding9, 0, sizeof (params->padding9));
/* Put the real mode code at the real location. */
grub_memmove (real_mode_mem, &lh, sizeof (lh));
len = real_size + GRUB_DISK_SECTOR_SIZE - sizeof (lh);
if (grub_file_read (file, (char *) real_mode_mem + sizeof (lh), len) != len)
{
grub_error (GRUB_ERR_FILE_READ_ERROR, "Couldn't read file");
goto fail;
}
#endif
/* The other EFI parameters are filled when booting. */
grub_file_seek (file, real_size + GRUB_DISK_SECTOR_SIZE);
/* XXX there is no way to know if the kernel really supports EFI. */
grub_printf (" [Linux-EFI, setup=0x%x, size=0x%x]\n",
real_size, prot_size);
grub_printf (" [Linux-bzImage, setup=0x%x, size=0x%x]\n",
(unsigned) real_size, (unsigned) prot_size);
grub_linux_setup_video (params);
/* Detect explicitly specified memory size, if any. */
linux_mem_size = 0;
@ -498,9 +818,9 @@ grub_rescue_cmd_linux (int argc, char *argv[])
if (grub_memcmp (argv[i], "mem=", 4) == 0)
{
char *val = argv[i] + 4;
linux_mem_size = grub_strtoul (val, &val, 0);
if (grub_errno)
{
grub_errno = GRUB_ERR_NONE;
@ -509,7 +829,7 @@ grub_rescue_cmd_linux (int argc, char *argv[])
else
{
int shift = 0;
switch (grub_tolower (val[0]))
{
case 'g':
@ -529,12 +849,17 @@ grub_rescue_cmd_linux (int argc, char *argv[])
linux_mem_size <<= shift;
}
}
else if (grub_memcmp (argv[i], "video=efifb", 11) == 0)
{
if (params->have_vga)
params->have_vga = GRUB_VIDEO_LINUX_TYPE_SIMPLE;
}
/* Specify the boot file. */
dest = grub_stpcpy ((char *) real_mode_mem + GRUB_LINUX_CL_OFFSET,
"BOOT_IMAGE=");
dest = grub_stpcpy (dest, argv[0]);
/* Copy kernel parameters. */
for (i = 1;
i < argc
@ -547,8 +872,8 @@ grub_rescue_cmd_linux (int argc, char *argv[])
}
len = prot_size;
if (grub_file_read (file, (char *) GRUB_LINUX_BZIMAGE_ADDR, len) != len)
grub_error (GRUB_ERR_FILE_READ_ERROR, "Couldn't read file");
if (grub_file_read (file, (void *) GRUB_LINUX_BZIMAGE_ADDR, len) != len)
grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file");
if (grub_errno == GRUB_ERR_NONE)
{
@ -557,7 +882,7 @@ grub_rescue_cmd_linux (int argc, char *argv[])
}
fail:
if (file)
grub_file_close (file);
@ -566,10 +891,13 @@ grub_rescue_cmd_linux (int argc, char *argv[])
grub_dl_unref (my_mod);
loaded = 0;
}
return grub_errno;
}
void
grub_rescue_cmd_initrd (int argc, char *argv[])
static grub_err_t
grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
int argc, char *argv[])
{
grub_file_t file = 0;
grub_ssize_t size;
@ -579,16 +907,16 @@ grub_rescue_cmd_initrd (int argc, char *argv[])
grub_efi_memory_descriptor_t *desc;
grub_efi_uintn_t desc_size;
struct linux_kernel_header *lh;
if (argc == 0)
{
grub_error (GRUB_ERR_BAD_ARGUMENT, "No module specified");
grub_error (GRUB_ERR_BAD_ARGUMENT, "no module specified");
goto fail;
}
if (! loaded)
{
grub_error (GRUB_ERR_BAD_ARGUMENT, "You need to load the kernel first.");
grub_error (GRUB_ERR_BAD_ARGUMENT, "you need to load the kernel first");
goto fail;
}
@ -600,11 +928,11 @@ grub_rescue_cmd_initrd (int argc, char *argv[])
initrd_pages = (page_align (size) >> 12);
lh = (struct linux_kernel_header *) real_mode_mem;
addr_max = grub_cpu_to_le32 (lh->initrd_addr_max);
addr_max = (grub_cpu_to_le32 (lh->initrd_addr_max) << 10);
if (linux_mem_size != 0 && linux_mem_size < addr_max)
addr_max = linux_mem_size;
/* Linux 2.3.xx has a bug in the memory range check, so avoid
the last page.
Linux 2.2.xx has a bug in the memory range check, which is
@ -612,8 +940,9 @@ grub_rescue_cmd_initrd (int argc, char *argv[])
addr_max -= 0x10000;
/* Usually, the compression ratio is about 50%. */
addr_min = (grub_addr_t) prot_mode_mem + ((prot_mode_pages * 3) << 12);
addr_min = (grub_addr_t) prot_mode_mem + ((prot_mode_pages * 3) << 12)
+ page_align (size);
/* Find the highest address to put the initrd. */
mmap_size = find_mmap_size ();
if (grub_efi_get_memory_map (&mmap_size, mmap_buf, 0, &desc_size, 0) <= 0)
@ -625,18 +954,23 @@ grub_rescue_cmd_initrd (int argc, char *argv[])
desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size))
{
if (desc->type == GRUB_EFI_CONVENTIONAL_MEMORY
&& desc->physical_start >= addr_min
&& desc->physical_start + size < addr_max
&& desc->num_pages >= initrd_pages)
{
grub_efi_physical_address_t physical_end;
physical_end = desc->physical_start + (desc->num_pages << 12);
if (physical_end > addr_max)
physical_end = addr_max;
if (physical_end > addr)
addr = physical_end - page_align (size);
if (physical_end < page_align (size))
continue;
physical_end -= page_align (size);
if ((physical_end >= addr_min) &&
(physical_end >= desc->physical_start) &&
(physical_end > addr))
addr = physical_end;
}
}
@ -645,43 +979,44 @@ grub_rescue_cmd_initrd (int argc, char *argv[])
grub_error (GRUB_ERR_OUT_OF_MEMORY, "no free pages available");
goto fail;
}
initrd_mem = grub_efi_allocate_pages (addr, initrd_pages);
if (! initrd_mem)
grub_fatal ("cannot allocate pages");
if (grub_file_read (file, initrd_mem, size) != size)
{
grub_error (GRUB_ERR_FILE_READ_ERROR, "Couldn't read file");
grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file");
goto fail;
}
grub_printf (" [Initrd, addr=0x%x, size=0x%x]\n",
addr, size);
(unsigned) addr, (unsigned) size);
lh->ramdisk_image = addr;
lh->ramdisk_size = size;
lh->root_dev = 0x0100; /* XXX */
fail:
if (file)
grub_file_close (file);
return grub_errno;
}
static grub_command_t cmd_linux, cmd_initrd;
GRUB_MOD_INIT(linux)
{
grub_rescue_register_command ("linux",
grub_rescue_cmd_linux,
"load linux");
grub_rescue_register_command ("initrd",
grub_rescue_cmd_initrd,
"load initrd");
cmd_linux = grub_register_command ("linux", grub_cmd_linux,
0, N_("Load Linux."));
cmd_initrd = grub_register_command ("initrd", grub_cmd_initrd,
0, N_("Load initrd."));
my_mod = mod;
}
GRUB_MOD_FINI(linux)
{
grub_rescue_unregister_command ("linux");
grub_rescue_unregister_command ("initrd");
grub_unregister_command (cmd_linux);
grub_unregister_command (cmd_initrd);
}

View file

@ -1,60 +0,0 @@
/* linux_normal.c - boot linux */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2004,2005,2006,2007 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/>.
*/
#include <grub/machine/loader.h>
#include <grub/err.h>
#include <grub/normal.h>
#include <grub/dl.h>
static grub_err_t
grub_normal_linux_command (struct grub_arg_list *state __attribute__ ((unused)),
int argc, char **args)
{
grub_rescue_cmd_linux (argc, args);
return grub_errno;
}
static grub_err_t
grub_normal_initrd_command (struct grub_arg_list *state __attribute__ ((unused)),
int argc, char **args)
{
grub_rescue_cmd_initrd (argc, args);
return grub_errno;
}
GRUB_MOD_INIT(linux_normal)
{
(void) mod; /* To stop warning. */
grub_register_command ("linux", grub_normal_linux_command,
GRUB_COMMAND_FLAG_BOTH,
"linux FILE [ARGS...]",
"Load a linux kernel.", 0);
grub_register_command ("initrd", grub_normal_initrd_command,
GRUB_COMMAND_FLAG_BOTH,
"initrd FILE",
"Load an initrd.", 0);
}
GRUB_MOD_FINI(linux_normal)
{
grub_unregister_command ("linux");
grub_unregister_command ("initrd");
}

178
loader/i386/efi/xnu.c Normal file
View file

@ -0,0 +1,178 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 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/>.
*/
#include <grub/env.h>
#include <grub/xnu.h>
#include <grub/cpu/xnu.h>
#include <grub/efi/api.h>
#include <grub/efi/efi.h>
#include <grub/efi/uga_draw.h>
#include <grub/pci.h>
#include <grub/misc.h>
/* Setup video for xnu. Big parts are copied from linux.c. */
static grub_efi_guid_t uga_draw_guid = GRUB_EFI_UGA_DRAW_GUID;
#define RGB_MASK 0xffffff
#define RGB_MAGIC 0x121314
#define LINE_MIN 800
#define LINE_MAX 4096
#define FBTEST_STEP (0x10000 >> 2)
#define FBTEST_COUNT 8
static int
find_line_len (grub_uint32_t *fb_base, grub_uint32_t *line_len)
{
grub_uint32_t *base = (grub_uint32_t *) (grub_target_addr_t) *fb_base;
int i;
for (i = 0; i < FBTEST_COUNT; i++, base += FBTEST_STEP)
{
if ((*base & RGB_MASK) == RGB_MAGIC)
{
int j;
for (j = LINE_MIN; j <= LINE_MAX; j++)
{
if ((base[j] & RGB_MASK) == RGB_MAGIC)
{
*fb_base = (grub_uint32_t) (grub_target_addr_t) base;
*line_len = j << 2;
return 1;
}
}
break;
}
}
return 0;
}
static int
find_framebuf (grub_uint32_t *fb_base, grub_uint32_t *line_len)
{
int found = 0;
auto int NESTED_FUNC_ATTR find_card (grub_pci_device_t dev,
grub_pci_id_t pciid);
int NESTED_FUNC_ATTR find_card (grub_pci_device_t dev,
grub_pci_id_t pciid)
{
grub_pci_address_t addr;
addr = grub_pci_make_address (dev, 2);
if (grub_pci_read (addr) >> 24 == 0x3)
{
int i;
grub_printf ("Display controller: %d:%d.%d\nDevice id: %x\n",
grub_pci_get_bus (dev), grub_pci_get_device (dev),
grub_pci_get_function (dev), pciid);
addr += 8;
for (i = 0; i < 6; i++, addr += 4)
{
grub_uint32_t old_bar1, old_bar2, type;
grub_uint64_t base64;
old_bar1 = grub_pci_read (addr);
if ((! old_bar1) || (old_bar1 & GRUB_PCI_ADDR_SPACE_IO))
continue;
type = old_bar1 & GRUB_PCI_ADDR_MEM_TYPE_MASK;
if (type == GRUB_PCI_ADDR_MEM_TYPE_64)
{
if (i == 5)
break;
old_bar2 = grub_pci_read (addr + 4);
}
else
old_bar2 = 0;
base64 = old_bar2;
base64 <<= 32;
base64 |= (old_bar1 & GRUB_PCI_ADDR_MEM_MASK);
grub_printf ("%s(%d): 0x%llx\n",
((old_bar1 & GRUB_PCI_ADDR_MEM_PREFETCH) ?
"VMEM" : "MMIO"), i,
(unsigned long long) base64);
if ((old_bar1 & GRUB_PCI_ADDR_MEM_PREFETCH) && (! found))
{
*fb_base = base64;
if (find_line_len (fb_base, line_len))
found++;
}
if (type == GRUB_PCI_ADDR_MEM_TYPE_64)
{
i++;
addr += 4;
}
}
}
return found;
}
grub_pci_iterate (find_card);
return found;
}
grub_err_t
grub_xnu_set_video (struct grub_xnu_boot_params *params)
{
grub_efi_uga_draw_protocol_t *c;
grub_uint32_t width, height, depth, rate, pixel, fb_base, line_len;
int ret;
c = grub_efi_locate_protocol (&uga_draw_guid, 0);
if (! c)
return grub_error (GRUB_ERR_IO, "couldn't find UGADraw");
if (efi_call_5 (c->get_mode, c, &width, &height, &depth, &rate))
return grub_error (GRUB_ERR_IO, "couldn't retrieve video mode");
grub_printf ("Video mode: %ux%u-%u@%u\n", width, height, depth, rate);
grub_efi_set_text_mode (0);
pixel = RGB_MAGIC;
efi_call_10 (c->blt, c, (struct grub_efi_uga_pixel *) &pixel,
GRUB_EFI_UGA_VIDEO_FILL, 0, 0, 0, 0, 1, height, 0);
ret = find_framebuf (&fb_base, &line_len);
grub_efi_set_text_mode (1);
if (! ret)
return grub_error (GRUB_ERR_IO, "can\'t find frame buffer address");
grub_printf ("Frame buffer base: 0x%x\n", fb_base);
grub_printf ("Video line length: %d\n", line_len);
params->lfb_width = width;
params->lfb_height = height;
params->lfb_depth = depth;
params->lfb_line_len = line_len;
params->lfb_mode = GRUB_XNU_VIDEO_TEXT_IN_VIDEO;
params->lfb_base = fb_base;
return GRUB_ERR_NONE;
}

View file

@ -0,0 +1,311 @@
/* linux.c - boot Linux zImage or bzImage */
/*
* 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/>.
*/
#include <grub/loader.h>
#include <grub/machine/loader.h>
#include <grub/machine/memory.h>
#include <grub/file.h>
#include <grub/err.h>
#include <grub/disk.h>
#include <grub/misc.h>
#include <grub/types.h>
#include <grub/mm.h>
#include <grub/dl.h>
#include <grub/env.h>
#include <grub/term.h>
#include <grub/cpu/linux.h>
#include <grub/ieee1275/ieee1275.h>
#include <grub/command.h>
#include <grub/i18n.h>
#define GRUB_OFW_LINUX_PARAMS_ADDR 0x90000
#define GRUB_OFW_LINUX_KERNEL_ADDR 0x100000
#define GRUB_OFW_LINUX_INITRD_ADDR 0x800000
#define GRUB_OFW_LINUX_CL_OFFSET 0x1e00
#define GRUB_OFW_LINUX_CL_LENGTH 0x100
static grub_dl_t my_mod;
static grub_size_t kernel_size;
static char *kernel_addr, *kernel_cmdline;
static grub_size_t initrd_size;
static grub_err_t
grub_linux_unload (void)
{
grub_free (kernel_cmdline);
grub_free (kernel_addr);
kernel_cmdline = 0;
kernel_addr = 0;
initrd_size = 0;
grub_dl_unref (my_mod);
return GRUB_ERR_NONE;
}
/*
static int
grub_ieee1275_debug (void)
{
struct enter_args
{
struct grub_ieee1275_common_hdr common;
}
args;
INIT_IEEE1275_COMMON (&args.common, "enter", 0, 0);
if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
return -1;
return 0;
}
*/
static grub_err_t
grub_linux_boot (void)
{
struct linux_kernel_params *params;
struct linux_kernel_header *lh;
char *prot_code;
char *bootpath;
grub_ssize_t len;
bootpath = grub_env_get ("root");
if (bootpath)
grub_ieee1275_set_property (grub_ieee1275_chosen,
"bootpath", bootpath,
grub_strlen (bootpath) + 1,
&len);
params = (struct linux_kernel_params *) GRUB_OFW_LINUX_PARAMS_ADDR;
lh = (struct linux_kernel_header *) params;
grub_memset ((char *) params, 0, GRUB_OFW_LINUX_CL_OFFSET);
params->alt_mem = grub_mmap_get_upper () >> 10;
params->ext_mem = params->alt_mem;
lh->cmd_line_ptr = (char *)
(GRUB_OFW_LINUX_PARAMS_ADDR + GRUB_OFW_LINUX_CL_OFFSET);
params->cl_magic = GRUB_LINUX_CL_MAGIC;
params->cl_offset = GRUB_OFW_LINUX_CL_OFFSET;
{
grub_term_output_t term;
int found = 0;
FOR_ACTIVE_TERM_OUTPUTS(term)
if (grub_strcmp (term->name, "ofconsole") == 0)
{
grub_uint16_t pos = grub_term_getxy (term);
params->video_cursor_x = pos >> 8;
params->video_cursor_y = pos & 0xff;
params->video_width = grub_term_width (term);
params->video_height = grub_term_height (term);
found = 1;
break;
}
if (!found)
{
params->video_cursor_x = 0;
params->video_cursor_y = 0;
params->video_width = 80;
params->video_height = 25;
}
}
params->font_size = 16;
params->ofw_signature = GRUB_LINUX_OFW_SIGNATURE;
params->ofw_num_items = 1;
params->ofw_cif_handler = (grub_uint32_t) grub_ieee1275_entry_fn;
params->ofw_idt = 0;
if (initrd_size)
{
lh->type_of_loader = 1;
lh->ramdisk_image = GRUB_OFW_LINUX_INITRD_ADDR;
lh->ramdisk_size = initrd_size;
}
if (kernel_cmdline)
grub_strcpy (lh->cmd_line_ptr, kernel_cmdline);
prot_code = (char *) GRUB_OFW_LINUX_KERNEL_ADDR;
grub_memcpy (prot_code, kernel_addr, kernel_size);
asm volatile ("movl %0, %%esi" : : "m" (params));
asm volatile ("movl %%esi, %%esp" : : );
asm volatile ("movl %0, %%ecx" : : "m" (prot_code));
asm volatile ("xorl %%ebx, %%ebx" : : );
asm volatile ("jmp *%%ecx" : : );
return GRUB_ERR_NONE;
}
static grub_err_t
grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
int argc, char *argv[])
{
grub_file_t file = 0;
struct linux_kernel_header lh;
grub_uint8_t setup_sects;
grub_size_t real_size, prot_size;
int i;
char *dest;
grub_dl_ref (my_mod);
if (argc == 0)
{
grub_error (GRUB_ERR_BAD_ARGUMENT, "no kernel specified");
goto fail;
}
file = grub_file_open (argv[0]);
if (! file)
goto fail;
if (grub_file_read (file, &lh, sizeof (lh)) != sizeof (lh))
{
grub_error (GRUB_ERR_READ_ERROR, "cannot read the Linux header");
goto fail;
}
if ((lh.boot_flag != grub_cpu_to_le16 (0xaa55)) ||
(lh.header != grub_cpu_to_le32 (GRUB_LINUX_MAGIC_SIGNATURE)))
{
grub_error (GRUB_ERR_BAD_OS, "invalid magic number");
goto fail;
}
setup_sects = lh.setup_sects;
if (! setup_sects)
setup_sects = GRUB_LINUX_DEFAULT_SETUP_SECTS;
real_size = setup_sects << GRUB_DISK_SECTOR_BITS;
prot_size = grub_file_size (file) - real_size - GRUB_DISK_SECTOR_SIZE;
grub_printf (" [Linux-%s, setup=0x%x, size=0x%x]\n",
"bzImage", real_size, prot_size);
grub_file_seek (file, real_size + GRUB_DISK_SECTOR_SIZE);
if (grub_errno)
goto fail;
kernel_cmdline = grub_malloc (GRUB_OFW_LINUX_CL_LENGTH);
if (! kernel_cmdline)
goto fail;
dest = kernel_cmdline;
for (i = 1;
i < argc
&& dest + grub_strlen (argv[i]) + 1 < (kernel_cmdline
+ GRUB_OFW_LINUX_CL_LENGTH);
i++)
{
*dest++ = ' ';
dest = grub_stpcpy (dest, argv[i]);
}
kernel_addr = grub_malloc (prot_size);
if (! kernel_addr)
goto fail;
kernel_size = prot_size;
if (grub_file_read (file, kernel_addr, prot_size) != (int) prot_size)
grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file");
if (grub_errno == GRUB_ERR_NONE)
grub_loader_set (grub_linux_boot, grub_linux_unload, 1);
fail:
if (file)
grub_file_close (file);
if (grub_errno != GRUB_ERR_NONE)
{
grub_free (kernel_cmdline);
grub_free (kernel_addr);
kernel_cmdline = 0;
kernel_addr = 0;
grub_dl_unref (my_mod);
}
return grub_errno;
}
static grub_err_t
grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
int argc, char *argv[])
{
grub_file_t file = 0;
if (argc == 0)
{
grub_error (GRUB_ERR_BAD_ARGUMENT, "no module specified");
goto fail;
}
if (! kernel_addr)
{
grub_error (GRUB_ERR_BAD_ARGUMENT, "you need to load the kernel first");
goto fail;
}
file = grub_file_open (argv[0]);
if (! file)
goto fail;
initrd_size = grub_file_size (file);
if (grub_file_read (file, (void *) GRUB_OFW_LINUX_INITRD_ADDR,
initrd_size) != (int) initrd_size)
{
grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file");
goto fail;
}
fail:
if (file)
grub_file_close (file);
return grub_errno;
}
static grub_command_t cmd_linux, cmd_initrd;
GRUB_MOD_INIT(linux)
{
cmd_linux = grub_register_command ("linux", grub_cmd_linux,
0, N_("Load Linux."));
cmd_initrd = grub_register_command ("initrd", grub_cmd_initrd,
0, N_("Load initrd."));
my_mod = mod;
}
GRUB_MOD_FINI(linux)
{
grub_unregister_command (cmd_linux);
grub_unregister_command (cmd_initrd);
}

1012
loader/i386/linux.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,129 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 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/>.
*/
#include <grub/symbol.h>
.p2align 4 /* force 16-byte alignment */
VARIABLE(grub_linux_trampoline_start)
cli
/* %rdi contains protected memory start and %rsi
contains real memory start. */
mov %rsi, %rbx
call base
base:
pop %rsi
#ifdef APPLE_CC
lea (cont1 - base) (%esi, 1), %rax
mov %eax, (jump_vector - base) (%esi, 1)
lea (gdt - base) (%esi, 1), %rax
mov %rax, (gdtaddr - base) (%esi, 1)
/* Switch to compatibility mode. */
lidt (idtdesc - base) (%esi, 1)
lgdt (gdtdesc - base) (%esi, 1)
/* Update %cs. Thanks to David Miller for pointing this mistake out. */
ljmp *(jump_vector - base) (%esi, 1)
#else
lea (cont1 - base) (%rsi, 1), %rax
mov %eax, (jump_vector - base) (%rsi, 1)
lea (gdt - base) (%rsi, 1), %rax
mov %rax, (gdtaddr - base) (%rsi, 1)
/* Switch to compatibility mode. */
lidt (idtdesc - base) (%rsi, 1)
lgdt (gdtdesc - base) (%rsi, 1)
/* Update %cs. Thanks to David Miller for pointing this mistake out. */
ljmp *(jump_vector - base) (%rsi, 1)
#endif
cont1:
.code32
/* Update other registers. */
mov $0x18, %eax
mov %eax, %ds
mov %eax, %es
mov %eax, %fs
mov %eax, %gs
mov %eax, %ss
/* Disable paging. */
mov %cr0, %eax
and $0x7fffffff, %eax
mov %eax, %cr0
/* Disable amd64. */
mov $0xc0000080, %ecx
rdmsr
and $0xfffffeff, %eax
wrmsr
/* Turn off PAE. */
movl %cr4, %eax
and $0xffffffcf, %eax
mov %eax, %cr4
jmp cont2
cont2:
.code32
mov %ebx, %esi
jmp *%edi
/* GDT. */
.p2align 4
gdt:
/* NULL. */
.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
/* Reserved. */
.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
/* Code segment. */
.byte 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x9A, 0xCF, 0x00
/* Data segment. */
.byte 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x92, 0xCF, 0x00
gdtdesc:
.word 31
gdtaddr:
.quad gdt
idtdesc:
.word 0
idtaddr:
.quad 0
.p2align 4
jump_vector:
/* Jump location. Is filled by the code */
.long 0
.long 0x10
VARIABLE(grub_linux_trampoline_end)

331
loader/i386/multiboot.c Normal file
View file

@ -0,0 +1,331 @@
/* 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

@ -0,0 +1,159 @@
/*
* 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

463
loader/i386/multiboot_mbi.c Normal file
View file

@ -0,0 +1,463 @@
/*
* 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/>.
*/
#include <grub/machine/memory.h>
#include <grub/memory.h>
#ifdef GRUB_MACHINE_PCBIOS
#include <grub/machine/biosnum.h>
#endif
#include <grub/multiboot.h>
#include <grub/cpu/multiboot.h>
#include <grub/disk.h>
#include <grub/device.h>
#include <grub/partition.h>
#include <grub/mm.h>
#include <grub/misc.h>
#include <grub/env.h>
#include <grub/video.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
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;
static int accepts_video;
void
grub_multiboot_set_accepts_video (int val)
{
accepts_video = val;
}
/* 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 ()
+ 256 * sizeof (struct multiboot_color);
}
/* 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);
}
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)
{
grub_err_t err;
struct grub_video_mode_info mode_info;
void *framebuffer;
grub_video_driver_id_t driv_id;
struct grub_video_palette_data palette[256];
err = set_video_mode ();
if (err)
{
grub_print_error ();
grub_errno = GRUB_ERR_NONE;
}
grub_video_get_palette (0, ARRAY_SIZE (palette), palette);
driv_id = grub_video_get_driver_id ();
if (driv_id == GRUB_VIDEO_DRIVER_NONE)
return GRUB_ERR_NONE;
err = grub_video_get_info_and_fini (&mode_info, &framebuffer);
if (err)
return err;
mbi->framebuffer_addr = (grub_addr_t) framebuffer;
mbi->framebuffer_pitch = mode_info.pitch;
mbi->framebuffer_width = mode_info.width;
mbi->framebuffer_height = mode_info.height;
mbi->framebuffer_bpp = mode_info.bpp;
if (mode_info.mode_type & GRUB_VIDEO_MODE_TYPE_INDEX_COLOR)
{
struct multiboot_color *mb_palette;
unsigned i;
mbi->framebuffer_type = MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED;
mbi->framebuffer_palette_addr = ptrdest;
mbi->framebuffer_palette_num_colors = mode_info.number_of_colors;
if (mbi->framebuffer_palette_num_colors > ARRAY_SIZE (palette))
mbi->framebuffer_palette_num_colors = ARRAY_SIZE (palette);
mb_palette = (struct multiboot_color *) ptrorig;
for (i = 0; i < mbi->framebuffer_palette_num_colors; i++)
{
mb_palette[i].red = palette[i].r;
mb_palette[i].green = palette[i].g;
mb_palette[i].blue = palette[i].b;
}
ptrorig += mbi->framebuffer_palette_num_colors
* sizeof (struct multiboot_color);
ptrdest += mbi->framebuffer_palette_num_colors
* sizeof (struct multiboot_color);
}
else
{
mbi->framebuffer_type = MULTIBOOT_FRAMEBUFFER_TYPE_RGB;
mbi->framebuffer_red_field_position = mode_info.green_field_pos;
mbi->framebuffer_red_mask_size = mode_info.green_mask_size;
mbi->framebuffer_green_field_position = mode_info.green_field_pos;
mbi->framebuffer_green_mask_size = mode_info.green_mask_size;
mbi->framebuffer_blue_field_position = mode_info.blue_field_pos;
mbi->framebuffer_blue_mask_size = mode_info.blue_mask_size;
}
mbi->flags |= MULTIBOOT_INFO_FRAMEBUFFER_INFO;
return GRUB_ERR_NONE;
}
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;
grub_err_t err;
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;
}
err = retrieve_video_parameters (mbi, ptrorig, ptrdest);
if (err)
{
grub_print_error ();
grub_errno = GRUB_ERR_NONE;
}
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;
}

View file

@ -1,7 +1,7 @@
/* chainloader.c - boot another boot loader */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2002,2004,2007 Free Software Foundation, Inc.
* Copyright (C) 2002,2004,2007,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
@ -29,8 +29,12 @@
#include <grub/machine/init.h>
#include <grub/partition.h>
#include <grub/machine/memory.h>
#include <grub/rescue.h>
#include <grub/dl.h>
#include <grub/command.h>
#include <grub/machine/biosnum.h>
#include <grub/i18n.h>
#include <grub/video.h>
#include <grub/mm.h>
static grub_dl_t my_mod;
static int boot_drive;
@ -39,6 +43,7 @@ static void *boot_part_addr;
static grub_err_t
grub_chainloader_boot (void)
{
grub_video_set_mode ("text", 0, 0);
grub_chainloader_real_boot (boot_drive, boot_part_addr);
/* Never reach here. */
@ -52,7 +57,7 @@ grub_chainloader_unload (void)
return GRUB_ERR_NONE;
}
void
static void
grub_chainloader_cmd (const char *filename, grub_chainloader_flags_t flags)
{
grub_file_t file = 0;
@ -62,13 +67,13 @@ grub_chainloader_cmd (const char *filename, grub_chainloader_flags_t flags)
void *part_addr = 0;
grub_dl_ref (my_mod);
file = grub_file_open (filename);
if (! file)
goto fail;
/* Read the first block. */
if (grub_file_read (file, (char *) 0x7C00, GRUB_DISK_SECTOR_SIZE)
if (grub_file_read (file, (void *) 0x7C00, GRUB_DISK_SECTOR_SIZE)
!= GRUB_DISK_SECTOR_SIZE)
{
if (grub_errno == GRUB_ERR_NONE)
@ -89,49 +94,39 @@ grub_chainloader_cmd (const char *filename, grub_chainloader_flags_t flags)
grub_file_close (file);
/* Obtain the partition table from the root device. */
drive = grub_get_root_biosnumber ();
dev = grub_device_open (0);
if (dev)
if (dev && dev->disk && dev->disk->partition)
{
grub_disk_t disk = dev->disk;
if (disk)
{
grub_partition_t p = disk->partition;
/* In i386-pc, the id is equal to the BIOS drive number. */
drive = (int) disk->id;
if (p)
{
grub_disk_read (disk, p->offset, 446, 64,
(char *) GRUB_MEMORY_MACHINE_PART_TABLE_ADDR);
part_addr = (void *) (GRUB_MEMORY_MACHINE_PART_TABLE_ADDR
+ (p->index << 4));
}
}
grub_device_close (dev);
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));
}
if (dev)
grub_device_close (dev);
/* Ignore errors. Perhaps it's not fatal. */
grub_errno = GRUB_ERR_NONE;
boot_drive = drive;
boot_part_addr = part_addr;
grub_loader_set (grub_chainloader_boot, grub_chainloader_unload, 1);
return;
fail:
if (file)
grub_file_close (file);
grub_dl_unref (my_mod);
}
static void
grub_rescue_cmd_chainloader (int argc, char *argv[])
static grub_err_t
grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
int argc, char *argv[])
{
grub_chainloader_flags_t flags = 0;
@ -141,24 +136,25 @@ grub_rescue_cmd_chainloader (int argc, char *argv[])
argc--;
argv++;
}
if (argc == 0)
grub_error (GRUB_ERR_BAD_ARGUMENT, "no file specified");
return grub_error (GRUB_ERR_BAD_ARGUMENT, "no file specified");
else
grub_chainloader_cmd (argv[0], flags);
return grub_errno;
}
static const char loader_name[] = "chainloader";
static grub_command_t cmd;
GRUB_MOD_INIT(chainloader)
{
grub_rescue_register_command (loader_name,
grub_rescue_cmd_chainloader,
"load another boot loader");
cmd = grub_register_command ("chainloader", grub_cmd_chainloader,
0, N_("Load another boot loader."));
my_mod = mod;
}
GRUB_MOD_FINI(chainloader)
{
grub_rescue_unregister_command (loader_name);
grub_unregister_command (cmd);
}

View file

@ -1,56 +0,0 @@
/* chainloader_normal.c - boot another boot loader */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2004,2007 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/>.
*/
#include <grub/machine/chainloader.h>
#include <grub/err.h>
#include <grub/normal.h>
#include <grub/dl.h>
static const struct grub_arg_option options[] =
{
{"force", 'f', 0, "skip bootsector magic number test", 0, 0},
{0, 0, 0, 0, 0, 0}
};
static grub_err_t
chainloader_command (struct grub_arg_list *state,
int argc, char **args)
{
grub_chainloader_flags_t flags = state[0].set ? GRUB_CHAINLOADER_FORCE : 0;
if (argc == 0)
grub_error (GRUB_ERR_BAD_ARGUMENT, "no file specified");
else
grub_chainloader_cmd (args[0], flags);
return grub_errno;
}
GRUB_MOD_INIT(chainloader_normal)
{
(void) mod; /* To stop warning. */
grub_register_command ("chainloader", chainloader_command,
GRUB_COMMAND_FLAG_BOTH,
"chainloader [-f] FILE",
"Prepare to boot another boot loader.", options);
}
GRUB_MOD_FINI(chainloader_normal)
{
grub_unregister_command ("chainloader");
}

View file

@ -1,7 +1,7 @@
/* linux.c - boot Linux zImage or bzImage */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2007,2008 Free Software Foundation, Inc.
* 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
@ -27,9 +27,15 @@
#include <grub/types.h>
#include <grub/machine/init.h>
#include <grub/machine/memory.h>
#include <grub/rescue.h>
#include <grub/dl.h>
#include <grub/cpu/linux.h>
#include <grub/command.h>
#include <grub/i18n.h>
#include <grub/mm.h>
#include <grub/video.h>
#define GRUB_LINUX_CL_OFFSET 0x9000
#define GRUB_LINUX_CL_END_OFFSET 0x90FF
static grub_dl_t my_mod;
@ -44,8 +50,19 @@ grub_linux_unload (void)
return GRUB_ERR_NONE;
}
void
grub_rescue_cmd_linux (int argc, char *argv[])
static grub_err_t
grub_linux16_boot (void)
{
grub_video_set_mode ("text", 0, 0);
grub_linux16_real_boot ();
/* Not reached. */
return GRUB_ERR_NONE;
}
static grub_err_t
grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
int argc, char *argv[])
{
grub_file_t file = 0;
struct linux_kernel_header lh;
@ -56,7 +73,7 @@ grub_rescue_cmd_linux (int argc, char *argv[])
char *dest;
grub_dl_ref (my_mod);
if (argc == 0)
{
grub_error (GRUB_ERR_BAD_ARGUMENT, "no kernel specified");
@ -75,9 +92,9 @@ grub_rescue_cmd_linux (int argc, char *argv[])
goto fail;
}
if (grub_file_read (file, (char *) &lh, sizeof (lh)) != sizeof (lh))
if (grub_file_read (file, &lh, sizeof (lh)) != sizeof (lh))
{
grub_error (GRUB_ERR_READ_ERROR, "cannot read the linux header");
grub_error (GRUB_ERR_READ_ERROR, "cannot read the Linux header");
goto fail;
}
@ -96,26 +113,27 @@ grub_rescue_cmd_linux (int argc, char *argv[])
grub_linux_is_bzimage = 0;
setup_sects = lh.setup_sects;
linux_mem_size = 0;
if (lh.header == grub_cpu_to_le32 (GRUB_LINUX_MAGIC_SIGNATURE)
&& grub_le_to_cpu16 (lh.version) >= 0x0200)
{
grub_linux_is_bzimage = (lh.loadflags & GRUB_LINUX_FLAG_BIG_KERNEL);
lh.type_of_loader = GRUB_LINUX_BOOT_LOADER_TYPE;
/* Put the real mode part at as a high location as possible. */
grub_linux_real_addr = (char *) (grub_lower_mem
- GRUB_LINUX_SETUP_MOVE_SIZE);
grub_linux_real_addr
= (char *) UINT_TO_PTR (grub_mmap_get_lower ()
- GRUB_LINUX_SETUP_MOVE_SIZE);
/* But it must not exceed the traditional area. */
if (grub_linux_real_addr > (char *) GRUB_LINUX_OLD_REAL_MODE_ADDR)
grub_linux_real_addr = (char *) GRUB_LINUX_OLD_REAL_MODE_ADDR;
if (grub_le_to_cpu16 (lh.version) >= 0x0201)
{
lh.heap_end_ptr = grub_cpu_to_le16 (GRUB_LINUX_HEAP_END_OFFSET);
lh.loadflags |= GRUB_LINUX_FLAG_CAN_USE_HEAP;
}
if (grub_le_to_cpu16 (lh.version) >= 0x0202)
lh.cmd_line_ptr = grub_linux_real_addr + GRUB_LINUX_CL_OFFSET;
else
@ -130,38 +148,37 @@ grub_rescue_cmd_linux (int argc, char *argv[])
/* Your kernel is quite old... */
lh.cl_magic = grub_cpu_to_le16 (GRUB_LINUX_CL_MAGIC);
lh.cl_offset = grub_cpu_to_le16 (GRUB_LINUX_CL_OFFSET);
setup_sects = GRUB_LINUX_DEFAULT_SETUP_SECTS;
grub_linux_real_addr = (char *) GRUB_LINUX_OLD_REAL_MODE_ADDR;
}
/* If SETUP_SECTS is not set, set it to the default (4). */
if (! setup_sects)
setup_sects = GRUB_LINUX_DEFAULT_SETUP_SECTS;
real_size = setup_sects << GRUB_DISK_SECTOR_BITS;
prot_size = grub_file_size (file) - real_size - GRUB_DISK_SECTOR_SIZE;
grub_linux_tmp_addr = (char *) GRUB_LINUX_BZIMAGE_ADDR + prot_size;
if (! grub_linux_is_bzimage
&& ((char *) GRUB_LINUX_ZIMAGE_ADDR + prot_size
> (grub_size_t) grub_linux_real_addr))
&& ((char *) GRUB_LINUX_ZIMAGE_ADDR + prot_size > grub_linux_real_addr))
{
grub_error (GRUB_ERR_BAD_OS, "too big zImage (0x%x > 0x%x), use bzImage instead",
(char *) GRUB_LINUX_ZIMAGE_ADDR + prot_size,
(grub_size_t) grub_linux_real_addr);
goto fail;
}
if (grub_linux_real_addr + GRUB_LINUX_SETUP_MOVE_SIZE
> (char *) grub_lower_mem)
> (char *) UINT_TO_PTR (grub_mmap_get_lower ()))
{
grub_error (GRUB_ERR_OUT_OF_RANGE,
"too small lower memory (0x%x > 0x%x)",
grub_linux_real_addr + GRUB_LINUX_SETUP_MOVE_SIZE,
(char *) grub_lower_mem);
grub_linux_real_addr + GRUB_LINUX_SETUP_MOVE_SIZE,
(int) grub_mmap_get_lower ());
goto fail;
}
@ -192,9 +209,9 @@ grub_rescue_cmd_linux (int argc, char *argv[])
else if (grub_memcmp (argv[i], "mem=", 4) == 0)
{
char *val = argv[i] + 4;
linux_mem_size = grub_strtoul (val, &val, 0);
if (grub_errno)
{
grub_errno = GRUB_ERR_NONE;
@ -203,7 +220,7 @@ grub_rescue_cmd_linux (int argc, char *argv[])
else
{
int shift = 0;
switch (grub_tolower (val[0]))
{
case 'g':
@ -230,7 +247,7 @@ grub_rescue_cmd_linux (int argc, char *argv[])
len = real_size + GRUB_DISK_SECTOR_SIZE - sizeof (lh);
if (grub_file_read (file, grub_linux_tmp_addr + sizeof (lh), len) != len)
{
grub_error (GRUB_ERR_FILE_READ_ERROR, "Couldn't read file");
grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file");
goto fail;
}
@ -247,7 +264,7 @@ grub_rescue_cmd_linux (int argc, char *argv[])
dest = grub_stpcpy (grub_linux_tmp_addr + GRUB_LINUX_CL_OFFSET,
"BOOT_IMAGE=");
dest = grub_stpcpy (dest, argv[0]);
/* Copy kernel parameters. */
for (i = 1;
i < argc
@ -260,18 +277,18 @@ grub_rescue_cmd_linux (int argc, char *argv[])
}
len = prot_size;
if (grub_file_read (file, (char *) GRUB_LINUX_BZIMAGE_ADDR, len) != len)
grub_error (GRUB_ERR_FILE_READ_ERROR, "Couldn't read file");
if (grub_file_read (file, (void *) GRUB_LINUX_BZIMAGE_ADDR, len) != len)
grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file");
if (grub_errno == GRUB_ERR_NONE)
{
grub_linux_prot_size = prot_size;
grub_loader_set (grub_linux_boot, grub_linux_unload, 1);
grub_loader_set (grub_linux16_boot, grub_linux_unload, 1);
loaded = 1;
}
fail:
if (file)
grub_file_close (file);
@ -280,10 +297,13 @@ grub_rescue_cmd_linux (int argc, char *argv[])
grub_dl_unref (my_mod);
loaded = 0;
}
return grub_errno;
}
void
grub_rescue_cmd_initrd (int argc, char *argv[])
static grub_err_t
grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
int argc, char *argv[])
{
grub_file_t file = 0;
grub_ssize_t size;
@ -292,13 +312,13 @@ grub_rescue_cmd_initrd (int argc, char *argv[])
if (argc == 0)
{
grub_error (GRUB_ERR_BAD_ARGUMENT, "No module specified");
grub_error (GRUB_ERR_BAD_ARGUMENT, "no module specified");
goto fail;
}
if (!loaded)
{
grub_error (GRUB_ERR_BAD_ARGUMENT, "You need to load the kernel first.");
grub_error (GRUB_ERR_BAD_ARGUMENT, "you need to load the kernel first");
goto fail;
}
@ -307,7 +327,7 @@ grub_rescue_cmd_initrd (int argc, char *argv[])
if (!(lh->header == grub_cpu_to_le32 (GRUB_LINUX_MAGIC_SIGNATURE)
&& grub_le_to_cpu16 (lh->version) >= 0x0200))
{
grub_error (GRUB_ERR_BAD_OS, "The kernel is too old for initrd.");
grub_error (GRUB_ERR_BAD_OS, "the kernel is too old for initrd");
goto fail;
}
@ -345,43 +365,46 @@ grub_rescue_cmd_initrd (int argc, char *argv[])
size = grub_file_size (file);
/* Put the initrd as high as possible, 4Ki aligned. */
/* Put the initrd as high as possible, 4KiB aligned. */
addr = (addr_max - size) & ~0xFFF;
if (addr < addr_min)
{
grub_error (GRUB_ERR_OUT_OF_RANGE, "The initrd is too big");
grub_error (GRUB_ERR_OUT_OF_RANGE, "the initrd is too big");
goto fail;
}
if (grub_file_read (file, (void *)addr, size) != size)
if (grub_file_read (file, (void *) addr, size) != size)
{
grub_error (GRUB_ERR_FILE_READ_ERROR, "Couldn't read file");
grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file");
goto fail;
}
lh->ramdisk_image = addr;
lh->ramdisk_size = size;
fail:
if (file)
grub_file_close (file);
return grub_errno;
}
static grub_command_t cmd_linux, cmd_initrd;
GRUB_MOD_INIT(linux)
GRUB_MOD_INIT(linux16)
{
grub_rescue_register_command ("linux",
grub_rescue_cmd_linux,
"load linux");
grub_rescue_register_command ("initrd",
grub_rescue_cmd_initrd,
"load initrd");
cmd_linux =
grub_register_command ("linux16", grub_cmd_linux,
0, N_("Load Linux."));
cmd_initrd =
grub_register_command ("initrd16", grub_cmd_initrd,
0, N_("Load initrd."));
my_mod = mod;
}
GRUB_MOD_FINI(linux)
GRUB_MOD_FINI(linux16)
{
grub_rescue_unregister_command ("linux");
grub_rescue_unregister_command ("initrd");
grub_unregister_command (cmd_linux);
grub_unregister_command (cmd_initrd);
}

View file

@ -1,60 +0,0 @@
/* linux_normal.c - boot another boot loader */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2004,2005,2007 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/>.
*/
#include <grub/machine/loader.h>
#include <grub/err.h>
#include <grub/normal.h>
#include <grub/dl.h>
static grub_err_t
grub_normal_linux_command (struct grub_arg_list *state __attribute__ ((unused)),
int argc, char **args)
{
grub_rescue_cmd_linux (argc, args);
return grub_errno;
}
static grub_err_t
grub_normal_initrd_command (struct grub_arg_list *state __attribute__ ((unused)),
int argc, char **args)
{
grub_rescue_cmd_initrd (argc, args);
return grub_errno;
}
GRUB_MOD_INIT(linux_normal)
{
(void) mod; /* To stop warning. */
grub_register_command ("linux", grub_normal_linux_command,
GRUB_COMMAND_FLAG_BOTH,
"linux FILE [ARGS...]",
"Load a linux kernel.", 0);
grub_register_command ("initrd", grub_normal_initrd_command,
GRUB_COMMAND_FLAG_BOTH,
"initrd FILE",
"Load an initrd.", 0);
}
GRUB_MOD_FINI(linux_normal)
{
grub_unregister_command ("linux");
grub_unregister_command ("initrd");
}

View file

@ -1,443 +0,0 @@
/* multiboot.c - boot a multiboot OS image. */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2003,2004,2005,2007 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
* - a.out support
* - boot device
* - symbol table
* - memory map
* - drives table
* - ROM configuration table
* - APM table
*/
#include <grub/loader.h>
#include <grub/machine/loader.h>
#include <grub/multiboot.h>
#include <grub/machine/init.h>
#include <grub/machine/memory.h>
#include <grub/elf.h>
#include <grub/file.h>
#include <grub/err.h>
#include <grub/rescue.h>
#include <grub/dl.h>
#include <grub/mm.h>
#include <grub/misc.h>
#include <grub/gzio.h>
extern grub_dl_t my_mod;
static struct grub_multiboot_info *mbi;
static grub_addr_t entry;
static grub_err_t
grub_multiboot_boot (void)
{
grub_multiboot_real_boot (entry, mbi);
/* Not reached. */
return GRUB_ERR_NONE;
}
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 grub_mod_list *) mbi->mods_addr)[i].mod_start);
grub_free ((void *)
((struct grub_mod_list *) mbi->mods_addr)[i].cmdline);
}
grub_free ((void *) mbi->mods_addr);
grub_free ((void *) mbi->cmdline);
grub_free (mbi);
}
mbi = 0;
grub_dl_unref (my_mod);
return GRUB_ERR_NONE;
}
/* Check if BUFFER contains ELF32. */
static int
grub_multiboot_is_elf32 (void *buffer)
{
Elf32_Ehdr *ehdr = (Elf32_Ehdr *) buffer;
return ehdr->e_ident[EI_CLASS] == ELFCLASS32;
}
static grub_err_t
grub_multiboot_load_elf32 (grub_file_t file, void *buffer)
{
Elf32_Ehdr *ehdr = (Elf32_Ehdr *) buffer;
Elf32_Phdr *phdr;
int i;
if (ehdr->e_ident[EI_CLASS] != ELFCLASS32)
return grub_error (GRUB_ERR_UNKNOWN_OS, "invalid ELF class");
if (grub_dl_check_header (ehdr, sizeof(Elf32_Ehdr)))
return grub_error (GRUB_ERR_UNKNOWN_OS, "no valid ELF header found");
if (ehdr->e_type != ET_EXEC)
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");
entry = ehdr->e_entry;
/* Load every loadable segment in memory. */
for (i = 0; i < ehdr->e_phnum; i++)
{
phdr = (Elf32_Phdr *) ((char *) buffer + ehdr->e_phoff
+ i * ehdr->e_phentsize);
if (phdr->p_type == PT_LOAD)
{
/* The segment should fit in the area reserved for the OS. */
if (phdr->p_paddr < grub_os_area_addr)
return grub_error (GRUB_ERR_BAD_OS,
"segment doesn't fit in memory reserved for the OS (0x%lx < 0x%lx)",
phdr->p_paddr, grub_os_area_addr);
if (phdr->p_paddr + phdr->p_memsz > grub_os_area_addr + grub_os_area_size)
return grub_error (GRUB_ERR_BAD_OS,
"segment doesn't fit in memory reserved for the OS (0x%lx > 0x%lx)",
phdr->p_paddr + phdr->p_memsz,
grub_os_area_addr + grub_os_area_size);
if (grub_file_seek (file, (grub_off_t) phdr->p_offset)
== (grub_off_t) -1)
return grub_error (GRUB_ERR_BAD_OS,
"invalid offset in program header");
if (grub_file_read (file, (void *) phdr->p_paddr, phdr->p_filesz)
!= (grub_ssize_t) phdr->p_filesz)
return grub_error (GRUB_ERR_BAD_OS,
"couldn't read segment from file");
if (phdr->p_filesz < phdr->p_memsz)
grub_memset ((char *) phdr->p_paddr + phdr->p_filesz, 0,
phdr->p_memsz - phdr->p_filesz);
}
}
return grub_errno;
}
/* Check if BUFFER contains ELF64. */
static int
grub_multiboot_is_elf64 (void *buffer)
{
Elf64_Ehdr *ehdr = (Elf64_Ehdr *) buffer;
return ehdr->e_ident[EI_CLASS] == ELFCLASS64;
}
static grub_err_t
grub_multiboot_load_elf64 (grub_file_t file, void *buffer)
{
Elf64_Ehdr *ehdr = (Elf64_Ehdr *) buffer;
Elf64_Phdr *phdr;
int i;
if (ehdr->e_ident[EI_CLASS] != ELFCLASS64)
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 != EM_X86_64)
return grub_error(GRUB_ERR_UNKNOWN_OS, "no valid ELF header found");
if (ehdr->e_type != ET_EXEC)
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");
/* We still in 32-bit mode */
if (ehdr->e_entry > 0xffffffff)
return grub_error (GRUB_ERR_BAD_OS, "invalid entry point for ELF64");
entry = ehdr->e_entry;
/* Load every loadable segment in memory. */
for (i = 0; i < ehdr->e_phnum; i++)
{
phdr = (Elf64_Phdr *) ((char *) buffer + ehdr->e_phoff
+ i * ehdr->e_phentsize);
if (phdr->p_type == PT_LOAD)
{
/* The segment should fit in the area reserved for the OS. */
if (phdr->p_paddr < (grub_uint64_t) grub_os_area_addr)
return grub_error (GRUB_ERR_BAD_OS,
"segment doesn't fit in memory reserved for the OS (0x%lx < 0x%lx)",
phdr->p_paddr, (grub_uint64_t) grub_os_area_addr);
if (phdr->p_paddr + phdr->p_memsz
> (grub_uint64_t) grub_os_area_addr + (grub_uint64_t) grub_os_area_size)
return grub_error (GRUB_ERR_BAD_OS,
"segment doesn't fit in memory reserved for the OS (0x%lx > 0x%lx)",
phdr->p_paddr + phdr->p_memsz,
(grub_uint64_t) grub_os_area_addr + (grub_uint64_t) grub_os_area_size);
if (grub_file_seek (file, (grub_off_t) phdr->p_offset)
== (grub_off_t) -1)
return grub_error (GRUB_ERR_BAD_OS,
"invalid offset in program header");
if (grub_file_read (file, (void *) ((grub_uint32_t) phdr->p_paddr),
phdr->p_filesz)
!= (grub_ssize_t) phdr->p_filesz)
return grub_error (GRUB_ERR_BAD_OS,
"couldn't read segment from file");
if (phdr->p_filesz < phdr->p_memsz)
grub_memset (((char *) ((grub_uint32_t) phdr->p_paddr)
+ phdr->p_filesz),
0,
phdr->p_memsz - phdr->p_filesz);
}
}
return grub_errno;
}
/* 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], *cmdline = 0, *p;
struct grub_multiboot_header *header;
grub_ssize_t len;
int i;
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 grub_multiboot_header *) buffer;
((char *) header <= buffer + len - 12) || (header = 0);
header = (struct grub_multiboot_header *) ((char *) header + 4))
{
if (header->magic == MULTIBOOT_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 & MULTIBOOT_UNSUPPORTED)
{
grub_error (GRUB_ERR_UNKNOWN_OS,
"Unsupported flag: 0x%x", header->flags);
goto fail;
}
if (grub_multiboot_load_elf (file, buffer) != GRUB_ERR_NONE)
goto fail;
mbi = grub_malloc (sizeof (struct grub_multiboot_info));
if (! mbi)
goto fail;
mbi->flags = MULTIBOOT_INFO_MEMORY;
/* Convert from bytes to kilobytes. */
mbi->mem_lower = grub_lower_mem / 1024;
mbi->mem_upper = grub_upper_mem / 1024;
for (i = 0, len = 0; i < argc; i++)
len += grub_strlen (argv[i]) + 1;
cmdline = p = grub_malloc (len);
if (! cmdline)
goto fail;
for (i = 0; i < argc; i++)
{
p = grub_stpcpy (p, argv[i]);
*(p++) = ' ';
}
/* Remove the space after the last word. */
*(--p) = '\0';
mbi->flags |= MULTIBOOT_INFO_CMDLINE;
mbi->cmdline = (grub_uint32_t) cmdline;
mbi->flags |= MULTIBOOT_INFO_BOOT_LOADER_NAME;
mbi->boot_loader_name = (grub_uint32_t) grub_strdup (PACKAGE_STRING);
grub_loader_set (grub_multiboot_boot, grub_multiboot_unload, 1);
fail:
if (file)
grub_file_close (file);
if (grub_errno != GRUB_ERR_NONE)
{
grub_free (cmdline);
grub_free (mbi);
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;
if (argc == 0)
{
grub_error (GRUB_ERR_BAD_ARGUMENT, "No module specified");
goto fail;
}
if (!mbi)
{
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;
if (grub_file_read (file, module, size) != size)
{
grub_error (GRUB_ERR_FILE_READ_ERROR, "Couldn't read file");
goto fail;
}
for (i = 0; i < argc; i++)
len += grub_strlen (argv[i]) + 1;
cmdline = p = grub_malloc (len);
if (! cmdline)
goto fail;
for (i = 0; i < argc; i++)
{
p = grub_stpcpy (p, argv[i]);
*(p++) = ' ';
}
/* Remove the space after the last word. */
*(--p) = '\0';
if (mbi->flags & MULTIBOOT_INFO_MODS)
{
struct grub_mod_list *modlist = (struct grub_mod_list *) mbi->mods_addr;
modlist = grub_realloc (modlist, (mbi->mods_count + 1)
* sizeof (struct grub_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 grub_mod_list *modlist = grub_malloc (sizeof (struct grub_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;
modlist->pad = 0;
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);
}
}

View file

@ -1,101 +0,0 @@
/* multiboot2.c - boot a multiboot 2 OS image. */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2007 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/>.
*/
#include <multiboot2.h>
#include <grub/multiboot2.h>
#include <grub/elf.h>
#include <grub/err.h>
#include <grub/machine/loader.h>
#include <grub/mm.h>
grub_err_t
grub_mb2_arch_elf32_hook (Elf32_Phdr *phdr, UNUSED grub_addr_t *addr)
{
Elf32_Addr paddr = phdr->p_paddr;
if ((paddr < grub_os_area_addr)
|| (paddr + phdr->p_memsz > grub_os_area_addr + grub_os_area_size))
return grub_error(GRUB_ERR_OUT_OF_RANGE,"Address 0x%x is out of range",
paddr);
return GRUB_ERR_NONE;
}
grub_err_t
grub_mb2_arch_elf64_hook (Elf64_Phdr *phdr, UNUSED grub_addr_t *addr)
{
Elf64_Addr paddr = phdr->p_paddr;
if ((paddr < grub_os_area_addr)
|| (paddr + phdr->p_memsz > grub_os_area_addr + grub_os_area_size))
return (GRUB_ERR_OUT_OF_RANGE,"Address 0x%x is out of range",
paddr);
return GRUB_ERR_NONE;
}
grub_err_t
grub_mb2_arch_module_alloc (grub_size_t size, grub_addr_t *addr)
{
grub_addr_t modaddr;
modaddr = grub_memalign (MULTIBOOT2_MOD_ALIGN, size);
if (! modaddr)
return grub_errno;
*addr = modaddr;
return GRUB_ERR_NONE;
}
grub_err_t
grub_mb2_arch_module_free (grub_addr_t addr, UNUSED grub_size_t size)
{
grub_free((void *) addr);
return GRUB_ERR_NONE;
}
void
grub_mb2_arch_boot (grub_addr_t entry, void *tags)
{
grub_multiboot2_real_boot (entry, tags);
}
void
grub_mb2_arch_unload (struct multiboot_tag_header *tags)
{
struct multiboot_tag_header *tag;
/* Free all module memory in the tag list. */
for_each_tag (tag, tags)
{
if (tag->key == MULTIBOOT2_TAG_MODULE)
{
struct multiboot_tag_module *module =
(struct multiboot_tag_module *) tag;
grub_free((void *) module->addr);
}
}
}
grub_err_t
grub_mb2_tags_arch_create (void)
{
/* XXX Create boot device et al. */
return GRUB_ERR_NONE;
}

View file

@ -1,60 +0,0 @@
/* multiboot_normal.c - boot another boot loader */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2004,2005,2007 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/>.
*/
#include <grub/machine/loader.h>
#include <grub/err.h>
#include <grub/normal.h>
#include <grub/dl.h>
static grub_err_t
grub_normal_cmd_multiboot (struct grub_arg_list *state __attribute__ ((unused)),
int argc, char **args)
{
grub_rescue_cmd_multiboot (argc, args);
return grub_errno;
}
static grub_err_t
grub_normal_cmd_module (struct grub_arg_list *state __attribute__ ((unused)),
int argc, char **args)
{
grub_rescue_cmd_module (argc, args);
return grub_errno;
}
GRUB_MOD_INIT(multiboot_normal)
{
(void) mod; /* To stop warning. */
grub_register_command ("multiboot", grub_normal_cmd_multiboot,
GRUB_COMMAND_FLAG_BOTH | GRUB_COMMAND_FLAG_NO_ARG_PARSE,
"multiboot FILE [ARGS...]",
"Load a Multiboot kernel.", 0);
grub_register_command ("module", grub_normal_cmd_module,
GRUB_COMMAND_FLAG_BOTH | GRUB_COMMAND_FLAG_NO_ARG_PARSE,
"module FILE [ARGS...]",
"Load a Multiboot module.", 0);
}
GRUB_MOD_FINI(multiboot_normal)
{
grub_unregister_command ("multiboot");
grub_unregister_command ("module");
}

108
loader/i386/pc/xnu.c Normal file
View file

@ -0,0 +1,108 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 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/>.
*/
#include <grub/env.h>
#include <grub/misc.h>
#include <grub/xnu.h>
#include <grub/mm.h>
#include <grub/cpu/xnu.h>
#include <grub/video_fb.h>
#define min(a,b) (((a) < (b)) ? (a) : (b))
#define max(a,b) (((a) > (b)) ? (a) : (b))
#define DEFAULT_VIDEO_MODE "auto"
/* Setup video for xnu. */
grub_err_t
grub_xnu_set_video (struct grub_xnu_boot_params *params)
{
struct grub_video_mode_info mode_info;
int ret;
char *tmp, *modevar;
void *framebuffer;
grub_err_t err;
modevar = grub_env_get ("gfxpayload");
/* Consider only graphical 32-bit deep modes. */
if (! modevar || *modevar == 0)
err = grub_video_set_mode (DEFAULT_VIDEO_MODE,
GRUB_VIDEO_MODE_TYPE_PURE_TEXT
| GRUB_VIDEO_MODE_TYPE_DEPTH_MASK,
32 << GRUB_VIDEO_MODE_TYPE_DEPTH_POS);
else
{
tmp = grub_malloc (grub_strlen (modevar)
+ sizeof (DEFAULT_VIDEO_MODE) + 1);
if (! tmp)
return grub_error (GRUB_ERR_OUT_OF_MEMORY,
"couldn't allocate temporary storag");
grub_sprintf (tmp, "%s;" DEFAULT_VIDEO_MODE, modevar);
err = grub_video_set_mode (tmp,
GRUB_VIDEO_MODE_TYPE_PURE_TEXT
| GRUB_VIDEO_MODE_TYPE_DEPTH_MASK,
32 << GRUB_VIDEO_MODE_TYPE_DEPTH_POS);
grub_free (tmp);
}
if (err)
return err;
if (grub_xnu_bitmap)
{
int x, y;
x = mode_info.width - grub_xnu_bitmap->mode_info.width;
x /= 2;
y = mode_info.height - grub_xnu_bitmap->mode_info.height;
y /= 2;
err = grub_video_blit_bitmap (grub_xnu_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,
mode_info.width),
min (grub_xnu_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;
}
ret = grub_video_get_info_and_fini (&mode_info, &framebuffer);
if (ret)
return grub_error (GRUB_ERR_IO, "couldn't retrieve video parameters");
params->lfb_width = mode_info.width;
params->lfb_height = mode_info.height;
params->lfb_depth = mode_info.bpp;
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;
return GRUB_ERR_NONE;
}

1037
loader/i386/xnu.c Normal file

File diff suppressed because it is too large Load diff

161
loader/macho.c Normal file
View file

@ -0,0 +1,161 @@
/* macho.c - load Mach-O files. */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 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/>.
*/
/* This Mach-O loader is incomplete and can load only non-relocatable segments.
This is however enough to boot xnu (otool -l and Mach-O specs for more info).
*/
#include <grub/err.h>
#include <grub/macho.h>
#include <grub/cpu/macho.h>
#include <grub/machoload.h>
#include <grub/file.h>
#include <grub/gzio.h>
#include <grub/misc.h>
#include <grub/mm.h>
grub_err_t
grub_macho_close (grub_macho_t macho)
{
grub_file_t file = macho->file;
grub_free (macho->cmds32);
grub_free (macho->cmds64);
grub_free (macho);
if (file)
grub_file_close (file);
return grub_errno;
}
grub_macho_t
grub_macho_file (grub_file_t file)
{
grub_macho_t macho;
union grub_macho_filestart filestart;
macho = grub_malloc (sizeof (*macho));
if (! macho)
return 0;
macho->file = file;
macho->offset32 = -1;
macho->offset64 = -1;
macho->end32 = -1;
macho->end64 = -1;
macho->cmds32 = 0;
macho->cmds64 = 0;
if (grub_file_seek (macho->file, 0) == (grub_off_t) -1)
goto fail;
if (grub_file_read (macho->file, &filestart, sizeof (filestart))
!= sizeof (filestart))
{
grub_error_push ();
grub_error (GRUB_ERR_READ_ERROR, "cannot read Mach-O header");
goto fail;
}
/* Is it a fat file? */
if (filestart.fat.magic == grub_be_to_cpu32 (GRUB_MACHO_FAT_MAGIC))
{
struct grub_macho_fat_arch *archs;
int i, narchs;
/* Load architecture description. */
narchs = grub_be_to_cpu32 (filestart.fat.nfat_arch);
if (grub_file_seek (macho->file, sizeof (struct grub_macho_fat_header))
== (grub_off_t) -1)
goto fail;
archs = grub_malloc (sizeof (struct grub_macho_fat_arch) * narchs);
if (!archs)
goto fail;
if (grub_file_read (macho->file, archs,
sizeof (struct grub_macho_fat_arch) * narchs)
!= (grub_ssize_t)sizeof(struct grub_macho_fat_arch) * narchs)
{
grub_free (archs);
grub_error_push ();
grub_error (GRUB_ERR_READ_ERROR, "cannot read Mach-O header");
goto fail;
}
for (i = 0; i < narchs; i++)
{
if (GRUB_MACHO_CPUTYPE_IS_HOST32
(grub_be_to_cpu32 (archs[i].cputype)))
{
macho->offset32 = grub_be_to_cpu32 (archs[i].offset);
macho->end32 = grub_be_to_cpu32 (archs[i].offset)
+ grub_be_to_cpu32 (archs[i].size);
}
if (GRUB_MACHO_CPUTYPE_IS_HOST64
(grub_be_to_cpu32 (archs[i].cputype)))
{
macho->offset64 = grub_be_to_cpu32 (archs[i].offset);
macho->end64 = grub_be_to_cpu32 (archs[i].offset)
+ grub_be_to_cpu32 (archs[i].size);
}
}
grub_free (archs);
}
/* Is it a thin 32-bit file? */
if (filestart.thin32.magic == GRUB_MACHO_MAGIC32)
{
macho->offset32 = 0;
macho->end32 = grub_file_size (file);
}
/* Is it a thin 64-bit file? */
if (filestart.thin64.magic == GRUB_MACHO_MAGIC64)
{
macho->offset64 = 0;
macho->end64 = grub_file_size (file);
}
grub_macho_parse32 (macho);
grub_macho_parse64 (macho);
return macho;
fail:
grub_macho_close (macho);
return 0;
}
grub_macho_t
grub_macho_open (const char *name)
{
grub_file_t file;
grub_macho_t macho;
file = grub_gzfile_open (name, 1);
if (! file)
return 0;
macho = grub_macho_file (file);
if (! macho)
grub_file_close (file);
return macho;
}

18
loader/macho32.c Normal file
View file

@ -0,0 +1,18 @@
#include <grub/cpu/macho.h>
#include <grub/machoload.h>
#define SUFFIX(x) x ## 32
typedef struct grub_macho_header32 grub_macho_header_t;
typedef struct grub_macho_segment32 grub_macho_segment_t;
typedef grub_uint32_t grub_macho_addr_t;
typedef struct grub_macho_thread32 grub_macho_thread_t;
#define offsetXX offset32
#define ncmdsXX ncmds32
#define cmdsizeXX cmdsize32
#define cmdsXX cmds32
#define endXX end32
#define XX "32"
#define GRUB_MACHO_MAGIC GRUB_MACHO_MAGIC32
#define GRUB_MACHO_CMD_SEGMENT GRUB_MACHO_CMD_SEGMENT32
#include "machoXX.c"

18
loader/macho64.c Normal file
View file

@ -0,0 +1,18 @@
#include <grub/cpu/macho.h>
#include <grub/machoload.h>
#define SUFFIX(x) x ## 64
typedef struct grub_macho_header64 grub_macho_header_t;
typedef struct grub_macho_segment64 grub_macho_segment_t;
typedef grub_uint64_t grub_macho_addr_t;
typedef struct grub_macho_thread64 grub_macho_thread_t;
#define offsetXX offset64
#define ncmdsXX ncmds64
#define cmdsizeXX cmdsize64
#define cmdsXX cmds64
#define endXX end64
#define XX "64"
#define GRUB_MACHO_MAGIC GRUB_MACHO_MAGIC64
#define GRUB_MACHO_CMD_SEGMENT GRUB_MACHO_CMD_SEGMENT64
#include "machoXX.c"

239
loader/machoXX.c Normal file
View file

@ -0,0 +1,239 @@
#include <grub/file.h>
#include <grub/mm.h>
#include <grub/misc.h>
#define min(a,b) (((a) < (b)) ? (a) : (b))
int
SUFFIX (grub_macho_contains_macho) (grub_macho_t macho)
{
return macho->offsetXX != -1;
}
void
SUFFIX (grub_macho_parse) (grub_macho_t macho)
{
grub_macho_header_t head;
/* Is there any candidate at all? */
if (macho->offsetXX == -1)
return;
/* Read header and check magic*/
if (grub_file_seek (macho->file, macho->offsetXX) == (grub_off_t) -1
|| grub_file_read (macho->file, &head, sizeof (head))
!= sizeof(head))
{
grub_error (GRUB_ERR_READ_ERROR, "cannot read Mach-O header");
macho->offsetXX = -1;
return;
}
if (head.magic != GRUB_MACHO_MAGIC)
{
grub_error (GRUB_ERR_BAD_OS, "invalid Mach-O " XX "-bit header");
macho->offsetXX = -1;
return;
}
/* Read commands. */
macho->ncmdsXX = head.ncmds;
macho->cmdsizeXX = head.sizeofcmds;
macho->cmdsXX = grub_malloc(macho->cmdsizeXX);
if (! macho->cmdsXX)
{
grub_error (GRUB_ERR_OUT_OF_MEMORY, "not enough memory to read commands");
return;
}
if (grub_file_read (macho->file, macho->cmdsXX,
(grub_size_t) macho->cmdsizeXX)
!= (grub_ssize_t) macho->cmdsizeXX)
{
grub_error (GRUB_ERR_READ_ERROR, "cannot read Mach-O header");
macho->offsetXX = -1;
}
}
typedef int NESTED_FUNC_ATTR (*grub_macho_iter_hook_t)
(grub_macho_t , struct grub_macho_cmd *,
void *);
static grub_err_t
grub_macho_cmds_iterate (grub_macho_t macho,
grub_macho_iter_hook_t hook,
void *hook_arg)
{
grub_uint8_t *hdrs = macho->cmdsXX;
int i;
if (! macho->cmdsXX)
return grub_error (GRUB_ERR_BAD_OS, "couldn't find " XX "-bit Mach-O");
for (i = 0; i < macho->ncmdsXX; i++)
{
struct grub_macho_cmd *hdr = (struct grub_macho_cmd *) hdrs;
if (hook (macho, hdr, hook_arg))
break;
hdrs += hdr->cmdsize;
}
return grub_errno;
}
grub_size_t
SUFFIX (grub_macho_filesize) (grub_macho_t macho)
{
if (SUFFIX (grub_macho_contains_macho) (macho))
return macho->endXX - macho->offsetXX;
return 0;
}
grub_err_t
SUFFIX (grub_macho_readfile) (grub_macho_t macho, void *dest)
{
grub_ssize_t read;
if (! SUFFIX (grub_macho_contains_macho) (macho))
return grub_error (GRUB_ERR_BAD_OS,
"couldn't read architecture-specific part");
if (grub_file_seek (macho->file, macho->offsetXX) == (grub_off_t) -1)
{
grub_error_push ();
return grub_error (GRUB_ERR_BAD_OS,
"invalid offset in program header");
}
read = grub_file_read (macho->file, dest,
macho->endXX - macho->offsetXX);
if (read != (grub_ssize_t) (macho->endXX - macho->offsetXX))
{
grub_error_push ();
return grub_error (GRUB_ERR_BAD_OS,
"couldn't read architecture-specific part");
}
return GRUB_ERR_NONE;
}
/* Calculate the amount of memory spanned by the segments. */
grub_err_t
SUFFIX (grub_macho_size) (grub_macho_t macho, grub_macho_addr_t *segments_start,
grub_macho_addr_t *segments_end, int flags)
{
int nr_phdrs = 0;
/* Run through the program headers to calculate the total memory size we
should claim. */
auto int NESTED_FUNC_ATTR calcsize (grub_macho_t _macho,
struct grub_macho_cmd *phdr, void *_arg);
int NESTED_FUNC_ATTR calcsize (grub_macho_t _macho __attribute__ ((unused)),
struct grub_macho_cmd *hdr0,
void *_arg __attribute__ ((unused)))
{
grub_macho_segment_t *hdr = (grub_macho_segment_t *) hdr0;
if (hdr->cmd != GRUB_MACHO_CMD_SEGMENT)
return 0;
if (! hdr->vmsize)
return 0;
if (! hdr->filesize && (flags & GRUB_MACHO_NOBSS))
return 0;
nr_phdrs++;
if (hdr->vmaddr < *segments_start)
*segments_start = hdr->vmaddr;
if (hdr->vmaddr + hdr->vmsize > *segments_end)
*segments_end = hdr->vmaddr + hdr->vmsize;
return 0;
}
*segments_start = (grub_macho_addr_t) -1;
*segments_end = 0;
grub_macho_cmds_iterate (macho, calcsize, 0);
if (nr_phdrs == 0)
return grub_error (GRUB_ERR_BAD_OS, "no program headers present");
if (*segments_end < *segments_start)
/* Very bad addresses. */
return grub_error (GRUB_ERR_BAD_OS, "bad program header load addresses");
return GRUB_ERR_NONE;
}
/* Load every loadable segment into memory specified by `_load_hook'. */
grub_err_t
SUFFIX (grub_macho_load) (grub_macho_t macho, char *offset, int flags)
{
grub_err_t err = 0;
auto int NESTED_FUNC_ATTR do_load(grub_macho_t _macho,
struct grub_macho_cmd *hdr0,
void *_arg __attribute__ ((unused)));
int NESTED_FUNC_ATTR do_load(grub_macho_t _macho,
struct grub_macho_cmd *hdr0,
void *_arg __attribute__ ((unused)))
{
grub_macho_segment_t *hdr = (grub_macho_segment_t *) hdr0;
if (hdr->cmd != GRUB_MACHO_CMD_SEGMENT)
return 0;
if (! hdr->filesize && (flags & GRUB_MACHO_NOBSS))
return 0;
if (! hdr->vmsize)
return 0;
if (grub_file_seek (_macho->file, hdr->fileoff
+ _macho->offsetXX) == (grub_off_t) -1)
{
grub_error_push ();
grub_error (GRUB_ERR_BAD_OS,
"invalid offset in program header");
return 1;
}
if (hdr->filesize)
{
grub_ssize_t read;
read = grub_file_read (_macho->file, offset + hdr->vmaddr,
min (hdr->filesize, hdr->vmsize));
if (read != (grub_ssize_t) min (hdr->filesize, hdr->vmsize))
{
/* XXX How can we free memory from `load_hook'? */
grub_error_push ();
err=grub_error (GRUB_ERR_BAD_OS,
"couldn't read segment from file: "
"wanted 0x%lx bytes; read 0x%lx bytes",
hdr->filesize, read);
return 1;
}
}
if (hdr->filesize < hdr->vmsize)
grub_memset (offset + hdr->vmaddr + hdr->filesize,
0, hdr->vmsize - hdr->filesize);
return 0;
}
grub_macho_cmds_iterate (macho, do_load, 0);
return err;
}
grub_macho_addr_t
SUFFIX (grub_macho_get_entry_point) (grub_macho_t macho)
{
grub_macho_addr_t entry_point = 0;
auto int NESTED_FUNC_ATTR hook(grub_macho_t _macho,
struct grub_macho_cmd *hdr,
void *_arg __attribute__ ((unused)));
int NESTED_FUNC_ATTR hook(grub_macho_t _macho __attribute__ ((unused)),
struct grub_macho_cmd *hdr,
void *_arg __attribute__ ((unused)))
{
if (hdr->cmd == GRUB_MACHO_CMD_THREAD)
entry_point = ((grub_macho_thread_t *) hdr)->entry_point;
return 0;
}
grub_macho_cmds_iterate (macho, hook, 0);
return entry_point;
}

View file

@ -1,460 +0,0 @@
/* multiboot2.c - boot a multiboot 2 OS image. */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2007 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/>.
*/
#include <multiboot2.h>
#include <grub/loader.h>
#include <grub/machine/loader.h>
#include <grub/multiboot2.h>
#include <grub/elfload.h>
#include <grub/file.h>
#include <grub/err.h>
#include <grub/rescue.h>
#include <grub/dl.h>
#include <grub/mm.h>
#include <grub/misc.h>
#include <grub/gzio.h>
static grub_addr_t entry;
extern grub_dl_t my_mod;
static char *grub_mb2_tags;
static char *grub_mb2_tags_pos;
static grub_size_t grub_mb2_tags_len;
static int grub_mb2_tags_count;
static void
grub_mb2_tags_free (void)
{
grub_dprintf ("loader", "Freeing all tags...\n");
grub_free (grub_mb2_tags);
grub_mb2_tags = 0;
grub_mb2_tags_pos = 0;
grub_mb2_tags_len = 0;
grub_mb2_tags_count = 0;
}
grub_err_t
grub_mb2_tag_alloc (grub_addr_t *addr, int key, grub_size_t len)
{
struct multiboot_tag_header *tag;
grub_size_t used;
grub_size_t needed;
grub_dprintf ("loader", "Allocating tag: key 0x%x, size 0x%lx.\n",
key, (unsigned long) len);
used = grub_mb2_tags_pos - grub_mb2_tags;
len = ALIGN_UP (len, sizeof (multiboot_word));
needed = used + len;
if (needed > grub_mb2_tags_len)
{
/* Allocate new buffer. */
grub_size_t newsize = needed * 2;
char *newarea;
grub_dprintf ("loader", "Reallocating tag buffer (new size 0x%lx).\n",
(unsigned long) newsize);
newarea = grub_malloc (newsize);
if (! newarea)
return grub_errno;
grub_memcpy (newarea, grub_mb2_tags, grub_mb2_tags_len);
grub_free (grub_mb2_tags);
grub_mb2_tags_len = newsize;
grub_mb2_tags = newarea;
grub_mb2_tags_pos = newarea + used;
}
tag = (struct multiboot_tag_header *) grub_mb2_tags_pos;
grub_mb2_tags_pos += len;
tag->key = key;
tag->len = len;
if (addr)
*addr = (grub_addr_t) tag;
grub_mb2_tags_count++;
grub_dprintf ("loader", "Allocated tag %u at %p.\n", grub_mb2_tags_count, tag);
return 0;
}
static grub_err_t
grub_mb2_tag_start_create (void)
{
return grub_mb2_tag_alloc (0, MULTIBOOT2_TAG_START,
sizeof (struct multiboot_tag_start));
}
static grub_err_t
grub_mb2_tag_name_create (void)
{
struct multiboot_tag_name *name;
grub_addr_t name_addr;
grub_err_t err;
const char *grub_version = PACKAGE_STRING;
err = grub_mb2_tag_alloc (&name_addr, MULTIBOOT2_TAG_NAME,
sizeof (struct multiboot_tag_name) +
sizeof (grub_version) + 1);
if (err)
return err;
name = (struct multiboot_tag_name *) name_addr;
grub_strcpy (name->name, grub_version);
return GRUB_ERR_NONE;
}
typedef grub_err_t (*tag_create_t) (void);
static tag_create_t grub_mb2_tag_creators[] = {
grub_mb2_tag_start_create,
grub_mb2_tag_name_create,
grub_mb2_tags_arch_create,
0,
};
static grub_err_t
grub_mb2_tags_create (void)
{
tag_create_t *creator;
grub_err_t err;
for (creator = grub_mb2_tag_creators; *creator != 0; creator++)
{
err = (*creator) ();
if (err)
goto error;
}
return GRUB_ERR_NONE;
error:
grub_error_push ();
grub_mb2_tags_free ();
grub_error_pop ();
return err;
}
static grub_err_t
grub_mb2_tags_finish (void)
{
struct multiboot_tag_start *start;
grub_err_t err;
/* Create the `end' tag. */
err = grub_mb2_tag_alloc (0, MULTIBOOT2_TAG_END,
sizeof (struct multiboot_tag_end));
if (err)
goto error;
/* We created the `start' tag first. Update it now. */
start = (struct multiboot_tag_start *) grub_mb2_tags;
start->size = grub_mb2_tags_pos - grub_mb2_tags;
return GRUB_ERR_NONE;
error:
grub_error_push ();
grub_mb2_tags_free ();
grub_error_pop ();
return err;
}
static grub_err_t
grub_mb2_boot (void)
{
grub_mb2_tags_finish ();
grub_dprintf ("loader", "Tags at %p\n", grub_mb2_tags);
grub_mb2_arch_boot (entry, grub_mb2_tags);
/* Not reached. */
return GRUB_ERR_NONE;
}
static grub_err_t
grub_mb2_unload (void)
{
struct multiboot_tag_header *tag;
struct multiboot_tag_header *tags =
(struct multiboot_tag_header *) grub_mb2_tags;
/* Free all module memory in the tag list. */
for_each_tag (tag, tags)
{
if (tag->key == MULTIBOOT2_TAG_MODULE)
{
struct multiboot_tag_module *module =
(struct multiboot_tag_module *) tag;
grub_free ((void *) module->addr);
}
}
/* Allow architecture to un-reserve memory. */
grub_mb2_arch_unload (tags);
/* Free the tags themselves. */
grub_mb2_tags_free ();
grub_dl_unref (my_mod);
return GRUB_ERR_NONE;
}
static grub_err_t
grub_mb2_load_other (UNUSED grub_file_t file, UNUSED void *buffer)
{
/* XXX Create module tag here. */
return grub_error (GRUB_ERR_UNKNOWN_OS, "currently only ELF is supported");
}
/* Create the tag containing the cmdline and the address of the module data. */
static grub_err_t
grub_mb2_tag_module_create (grub_addr_t modaddr, grub_size_t modsize,
char *type, int key, int argc, char *argv[])
{
struct multiboot_tag_module *module;
grub_ssize_t argslen = 0;
grub_err_t err;
char *p;
grub_addr_t module_addr;
int i;
/* Allocate enough space for the arguments and spaces between them. */
for (i = 0; i < argc; i++)
argslen += grub_strlen (argv[i]) + 1;
/* Note: includes implicit 1-byte cmdline. */
err = grub_mb2_tag_alloc (&module_addr, key,
sizeof (struct multiboot_tag_module) + argslen);
if (err)
return grub_errno;
module = (struct multiboot_tag_module *) module_addr;
module->addr = modaddr;
module->size = modsize;
grub_strcpy(module->type, type);
/* Fill in the command line. */
p = module->cmdline;
for (i = 0; i < argc; i++)
{
p = grub_stpcpy (p, argv[i]);
*p++ = ' ';
}
module->cmdline[argslen] = '\0';
return GRUB_ERR_NONE;
}
/* Load ELF32 or ELF64. */
static grub_err_t
grub_mb2_load_elf (grub_elf_t elf, int argc, char *argv[])
{
grub_addr_t kern_base;
grub_size_t kern_size;
grub_err_t err;
if (grub_elf_is_elf32 (elf))
{
entry = elf->ehdr.ehdr32.e_entry;
err = grub_elf32_load (elf, grub_mb2_arch_elf32_hook, &kern_base,
&kern_size);
}
else if (grub_elf_is_elf64 (elf))
{
entry = elf->ehdr.ehdr64.e_entry;
err = grub_elf64_load (elf, grub_mb2_arch_elf64_hook, &kern_base,
&kern_size);
}
else
err = grub_error (GRUB_ERR_UNKNOWN_OS, "unknown ELF class");
if (err)
goto fail;
grub_dprintf ("loader", "Entry point is 0x%lx.\n", (unsigned long) entry);
grub_mb2_tag_module_create (kern_base, kern_size, "kernel",
MULTIBOOT2_TAG_MODULE, argc, argv);
fail:
return err;
}
void
grub_multiboot2 (int argc, char *argv[])
{
char *buffer;
grub_file_t file = 0;
grub_elf_t elf = 0;
struct multiboot_header *header = 0;
char *p;
grub_ssize_t len;
grub_err_t err;
int header_found = 0;
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;
}
buffer = grub_malloc (MULTIBOOT2_HEADER_SEARCH);
if (! buffer)
return;
len = grub_file_read (file, buffer, MULTIBOOT2_HEADER_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 (p = buffer; p <= buffer + len - 12; p += 4)
{
header = (struct multiboot_header *) p;
if (header->magic == MULTIBOOT2_HEADER_MAGIC)
{
header_found = 1;
break;
}
}
if (! header_found)
grub_dprintf ("loader", "No multiboot 2 header found.\n");
/* Create the basic tags. */
grub_dprintf ("loader", "Creating multiboot 2 tags\n");
grub_mb2_tags_create ();
/* Load the kernel and create its tag. */
elf = grub_elf_file (file);
if (elf)
{
grub_dprintf ("loader", "Loading ELF multiboot 2 file.\n");
err = grub_mb2_load_elf (elf, argc-1, &argv[1]);
grub_elf_close (elf);
}
else
{
grub_dprintf ("loader", "Loading non-ELF multiboot 2 file.\n");
if (header)
err = grub_mb2_load_other (file, header);
else
err = grub_error (GRUB_ERR_BAD_OS,
"Need multiboot 2 header to load non-ELF files.");
grub_file_close (file);
}
grub_free (buffer);
if (err)
goto fail;
/* Good to go. */
grub_loader_set (grub_mb2_boot, grub_mb2_unload, 1);
return;
fail:
grub_mb2_tags_free ();
grub_dl_unref (my_mod);
}
void
grub_module2 (int argc, char *argv[])
{
grub_file_t file;
grub_addr_t modaddr = 0;
grub_ssize_t modsize = 0;
grub_err_t err;
if (argc == 0)
{
grub_error (GRUB_ERR_BAD_ARGUMENT, "No module specified");
return;
}
if (argc == 1)
{
grub_error (GRUB_ERR_BAD_ARGUMENT, "No module type specified");
return;
}
if (entry == 0)
{
grub_error (GRUB_ERR_BAD_ARGUMENT,
"You need to load the multiboot kernel first");
return;
}
/* Load module data. */
file = grub_gzfile_open (argv[0], 1);
if (! file)
goto out;
modsize = grub_file_size (file);
err = grub_mb2_arch_module_alloc (modsize, &modaddr);
if (err)
goto out;
grub_dprintf ("loader", "Loading module at 0x%x - 0x%x\n", modaddr,
modaddr + modsize);
if (grub_file_read (file, (char *) modaddr, modsize) != modsize)
{
grub_error (GRUB_ERR_FILE_READ_ERROR, "Couldn't read file");
goto out;
}
/* Create the module tag. */
err = grub_mb2_tag_module_create (modaddr, modsize,
argv[1], MULTIBOOT2_TAG_MODULE,
argc-2, &argv[2]);
if (err)
goto out;
out:
grub_error_push ();
if (file)
grub_file_close (file);
if (modaddr)
grub_mb2_arch_module_free (modaddr, modsize);
grub_error_pop ();
}

View file

@ -1,7 +1,7 @@
/* multiboot_loader.c - boot multiboot 1 or 2 OS image */
/* multiboot_loader.c - boot multiboot kernel image */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2007 Free Software Foundation, Inc.
* Copyright (C) 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
@ -17,50 +17,38 @@
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#include <multiboot2.h>
#include <grub/machine/machine.h>
#include <grub/multiboot_loader.h>
#include <grub/multiboot.h>
#include <grub/multiboot2.h>
#include <grub/elf.h>
#include <grub/file.h>
#include <grub/err.h>
#include <grub/rescue.h>
#include <grub/dl.h>
#include <grub/mm.h>
#include <grub/misc.h>
#include <grub/gzio.h>
#include <grub/command.h>
#include <grub/i18n.h>
grub_dl_t my_mod;
/* This tracks which version of multiboot to use when using
* the module command. By default use multiboot version 1.
* values:
* 1 - Multiboot version 1
* 2 - Multiboot version 2
*/
static unsigned int module_version_status = 1;
static int
find_multi_boot1_header (grub_file_t file)
{
struct grub_multiboot_header *header;
struct multiboot_header *header;
char buffer[MULTIBOOT_SEARCH];
int found_status = 0;
grub_ssize_t len;
len = grub_file_read (file, buffer, MULTIBOOT_SEARCH);
if (len < 32)
return found_status;
/* 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 grub_multiboot_header *) buffer;
for (header = (struct multiboot_header *) buffer;
((char *) header <= buffer + len - 12) || (header = 0);
header = (struct grub_multiboot_header *) ((char *) header + 4))
header = (struct multiboot_header *) ((char *) header + 4))
{
if (header->magic == MULTIBOOT_MAGIC
if (header->magic == MULTIBOOT_HEADER_MAGIC
&& !(header->magic + header->flags + header->checksum))
{
found_status = 1;
@ -71,10 +59,10 @@ find_multi_boot1_header (grub_file_t file)
return found_status;
}
void
grub_rescue_cmd_multiboot_loader (int argc, char *argv[])
static grub_err_t
grub_cmd_multiboot_loader (grub_command_t cmd __attribute__ ((unused)),
int argc, char *argv[])
{
grub_file_t file = 0;
int header_multi_ver_found = 0;
@ -82,96 +70,81 @@ grub_rescue_cmd_multiboot_loader (int argc, char *argv[])
if (argc == 0)
{
grub_error (GRUB_ERR_BAD_ARGUMENT, "No kernel specified");
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");
grub_error (GRUB_ERR_BAD_ARGUMENT, "couldn't open file");
goto fail;
}
/* find which header is in the file */
if (find_multi_boot1_header(file))
if (find_multi_boot1_header (file))
header_multi_ver_found = 1;
else
{
/* The behavior is that if you don't find a multiboot 1 header
use multiboot 2 loader (as you do not have to have a header
to use multiboot 2 */
grub_dprintf ("multiboot_loader", "No multiboot 1 header found. \n \
Using multiboot 2 loader\n");
header_multi_ver_found = 0;
grub_error (GRUB_ERR_BAD_OS, "multiboot header not found");
goto fail;
}
/* close file before calling functions */
if (file)
grub_file_close (file);
/* close file before calling functions */
if (file)
grub_file_close (file);
/* Launch multi boot with header */
/* Launch multi boot with header */
/* XXX Find a better way to identify this.
This is for i386-pc */
#ifdef GRUB_MACHINE_PCBIOS
if (header_multi_ver_found == 1)
{
grub_dprintf ("multiboot_loader",
"Launching multiboot 1 grub_multiboot() function\n");
grub_multiboot (argc, argv);
module_version_status = 1;
}
#endif
if (header_multi_ver_found == 0 || header_multi_ver_found == 2)
{
grub_dprintf ("multiboot_loader",
"Launching multiboot 2 grub_multiboot2() function\n");
grub_multiboot2 (argc, argv);
module_version_status = 2;
}
grub_dprintf ("multiboot_loader",
"Launching multiboot 1 grub_multiboot() function\n");
grub_multiboot (argc, argv);
return;
return grub_errno;
fail:
if (file)
grub_file_close (file);
grub_file_close (file);
grub_dl_unref (my_mod);
return grub_errno;
}
void
grub_rescue_cmd_module_loader (int argc, char *argv[])
static grub_err_t
grub_cmd_module_loader (grub_command_t cmd __attribute__ ((unused)),
int argc, char *argv[])
{
#ifdef GRUB_MACHINE_PCBIOS
if (module_version_status == 1)
{
grub_dprintf("multiboot_loader",
"Launching multiboot 1 grub_module() function\n");
grub_module (argc, argv);
}
#endif
if (module_version_status == 2)
{
grub_dprintf("multiboot_loader",
"Launching multiboot 2 grub_module2() function\n");
grub_module2 (argc, argv);
}
grub_dprintf("multiboot_loader",
"Launching multiboot 1 grub_module() function\n");
grub_module (argc, argv);
return grub_errno;
}
static grub_command_t cmd_multiboot, cmd_module;
GRUB_MOD_INIT(multiboot)
{
grub_rescue_register_command ("multiboot", grub_rescue_cmd_multiboot_loader,
"load a multiboot kernel");
grub_rescue_register_command ("module", grub_rescue_cmd_module_loader,
"load a multiboot module");
cmd_multiboot =
#ifdef GRUB_USE_MULTIBOOT2
grub_register_command ("multiboot2", grub_cmd_multiboot_loader,
0, N_("Load a multiboot 2 kernel."));
#else
grub_register_command ("multiboot", grub_cmd_multiboot_loader,
0, N_("Load a multiboot kernel."));
#endif
cmd_module =
grub_register_command ("module", grub_cmd_module_loader,
0, N_("Load a multiboot module."));
my_mod = mod;
}
GRUB_MOD_FINI(multiboot)
{
grub_rescue_unregister_command ("multiboot");
grub_rescue_unregister_command ("module");
grub_unregister_command (cmd_multiboot);
grub_unregister_command (cmd_module);
}

View file

@ -1,61 +0,0 @@
/* multiboot_loader_normal.c - boot another boot loader */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2007 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/>.
*/
#include <grub/err.h>
#include <grub/normal.h>
#include <grub/dl.h>
#include <grub/multiboot_loader.h>
static grub_err_t
grub_normal_cmd_multiboot (struct grub_arg_list *state __attribute__ ((unused)),
int argc, char **args)
{
grub_rescue_cmd_multiboot_loader (argc, args);
return grub_errno;
}
static grub_err_t
grub_normal_cmd_module (struct grub_arg_list *state __attribute__ ((unused)),
int argc, char **args)
{
grub_rescue_cmd_module_loader (argc, args);
return grub_errno;
}
GRUB_MOD_INIT(multiboot_loader_normal)
{
(void) mod; /* To stop warning. */
grub_register_command ("multiboot", grub_normal_cmd_multiboot,
GRUB_COMMAND_FLAG_BOTH
| GRUB_COMMAND_FLAG_NO_ARG_PARSE,
"multiboot FILE [ARGS...]",
"Load a Multiboot kernel.", 0);
grub_register_command ("module", grub_normal_cmd_module,
GRUB_COMMAND_FLAG_BOTH
| GRUB_COMMAND_FLAG_NO_ARG_PARSE,
"module FILE [ARGS...]",
"Load a Multiboot module.", 0);
}
GRUB_MOD_FINI(multiboot_loader_normal)
{
grub_unregister_command ("multiboot");
grub_unregister_command ("module");
}

View file

@ -1,7 +1,7 @@
/* linux.c - boot Linux */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2003, 2004, 2005, 2007 Free Software Foundation, Inc.
* Copyright (C) 2003,2004,2005,2007,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
@ -22,10 +22,11 @@
#include <grub/loader.h>
#include <grub/dl.h>
#include <grub/mm.h>
#include <grub/rescue.h>
#include <grub/misc.h>
#include <grub/ieee1275/ieee1275.h>
#include <grub/machine/loader.h>
#include <grub/command.h>
#include <grub/i18n.h>
#define ELF32_LOADMASK (0xc0000000UL)
#define ELF64_LOADMASK (0xc000000000000000ULL)
@ -75,10 +76,10 @@ grub_linux_release_mem (void)
linux_args = 0;
if (linux_addr && grub_ieee1275_release (linux_addr, linux_size))
return grub_error (GRUB_ERR_OUT_OF_MEMORY, "Can not release memory");
return grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot release memory");
if (initrd_addr && grub_ieee1275_release (initrd_addr, initrd_size))
return grub_error (GRUB_ERR_OUT_OF_MEMORY, "Can not release memory");
return grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot release memory");
linux_addr = 0;
initrd_addr = 0;
@ -128,12 +129,19 @@ grub_linux_load32 (grub_elf_t elf)
break;
}
if (found_addr == -1)
return grub_error (GRUB_ERR_OUT_OF_MEMORY, "Could not claim memory.");
return grub_error (GRUB_ERR_OUT_OF_MEMORY, "couldn't claim memory");
/* Now load the segments into the area we claimed. */
auto grub_err_t offset_phdr (Elf32_Phdr *phdr, grub_addr_t *addr);
grub_err_t offset_phdr (Elf32_Phdr *phdr, grub_addr_t *addr)
auto grub_err_t offset_phdr (Elf32_Phdr *phdr, grub_addr_t *addr, int *do_load);
grub_err_t offset_phdr (Elf32_Phdr *phdr, grub_addr_t *addr, int *do_load)
{
if (phdr->p_type != PT_LOAD)
{
*do_load = 0;
return 0;
}
*do_load = 1;
/* Linux's program headers incorrectly contain virtual addresses.
* Translate those to physical, and offset to the area we claimed. */
*addr = (phdr->p_paddr & ~ELF32_LOADMASK) + linux_addr;
@ -171,12 +179,18 @@ grub_linux_load64 (grub_elf_t elf)
break;
}
if (found_addr == -1)
return grub_error (GRUB_ERR_OUT_OF_MEMORY, "Could not claim memory.");
return grub_error (GRUB_ERR_OUT_OF_MEMORY, "couldn't claim memory");
/* Now load the segments into the area we claimed. */
auto grub_err_t offset_phdr (Elf64_Phdr *phdr, grub_addr_t *addr);
grub_err_t offset_phdr (Elf64_Phdr *phdr, grub_addr_t *addr)
auto grub_err_t offset_phdr (Elf64_Phdr *phdr, grub_addr_t *addr, int *do_load);
grub_err_t offset_phdr (Elf64_Phdr *phdr, grub_addr_t *addr, int *do_load)
{
if (phdr->p_type != PT_LOAD)
{
*do_load = 0;
return 0;
}
*do_load = 1;
/* Linux's program headers incorrectly contain virtual addresses.
* Translate those to physical, and offset to the area we claimed. */
*addr = (phdr->p_paddr & ~ELF64_LOADMASK) + linux_addr;
@ -185,8 +199,9 @@ grub_linux_load64 (grub_elf_t elf)
return grub_elf64_load (elf, offset_phdr, 0, 0);
}
void
grub_rescue_cmd_linux (int argc, char *argv[])
static grub_err_t
grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
int argc, char *argv[])
{
grub_elf_t elf = 0;
int i;
@ -208,7 +223,7 @@ grub_rescue_cmd_linux (int argc, char *argv[])
if (elf->ehdr.ehdr32.e_type != ET_EXEC)
{
grub_error (GRUB_ERR_UNKNOWN_OS,
"This ELF file is not of the right type\n");
"this ELF file is not of the right type");
goto out;
}
@ -222,7 +237,7 @@ grub_rescue_cmd_linux (int argc, char *argv[])
grub_linux_load64 (elf);
else
{
grub_error (GRUB_ERR_BAD_FILE_TYPE, "Unknown ELF class");
grub_error (GRUB_ERR_BAD_FILE_TYPE, "unknown ELF class");
goto out;
}
@ -237,7 +252,7 @@ grub_rescue_cmd_linux (int argc, char *argv[])
/* Specify the boot file. */
dest = grub_stpcpy (linux_args, "BOOT_IMAGE=");
dest = grub_stpcpy (dest, argv[0]);
for (i = 1; i < argc; i++)
{
*dest++ = ' ';
@ -261,10 +276,13 @@ out:
initrd_addr = 0;
loaded = 1;
}
return grub_errno;
}
void
grub_rescue_cmd_initrd (int argc, char *argv[])
static grub_err_t
grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
int argc, char *argv[])
{
grub_file_t file = 0;
grub_ssize_t size;
@ -280,7 +298,7 @@ grub_rescue_cmd_initrd (int argc, char *argv[])
if (!loaded)
{
grub_error (GRUB_ERR_BAD_ARGUMENT, "You need to load the kernel first.");
grub_error (GRUB_ERR_BAD_ARGUMENT, "you need to load the kernel first");
goto fail;
}
@ -293,9 +311,9 @@ grub_rescue_cmd_initrd (int argc, char *argv[])
/* Attempt to claim at a series of addresses until successful in
the same way that grub_rescue_cmd_linux does. */
for (addr = first_addr; addr < first_addr + 200 * 0x100000; addr += 0x100000)
for (addr = first_addr; addr < first_addr + 200 * 0x100000; addr += 0x100000)
{
grub_dprintf ("loader", "Attempting to claim at 0x%x, size 0x%x.\n",
grub_dprintf ("loader", "Attempting to claim at 0x%x, size 0x%x.\n",
addr, size);
found_addr = grub_claimmap (addr, size);
if (found_addr != -1)
@ -304,7 +322,7 @@ grub_rescue_cmd_initrd (int argc, char *argv[])
if (found_addr == -1)
{
grub_error (GRUB_ERR_OUT_OF_MEMORY, "Can not claim memory");
grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot claim memory");
goto fail;
}
@ -313,7 +331,7 @@ grub_rescue_cmd_initrd (int argc, char *argv[])
if (grub_file_read (file, (void *) addr, size) != size)
{
grub_ieee1275_release (addr, size);
grub_error (GRUB_ERR_FILE_READ_ERROR, "Couldn't read file");
grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file");
goto fail;
}
@ -323,21 +341,23 @@ grub_rescue_cmd_initrd (int argc, char *argv[])
fail:
if (file)
grub_file_close (file);
return grub_errno;
}
static grub_command_t cmd_linux, cmd_initrd;
GRUB_MOD_INIT(linux)
{
grub_rescue_register_command ("linux", grub_rescue_cmd_linux,
"load a linux kernel");
grub_rescue_register_command ("initrd", grub_rescue_cmd_initrd,
"load an initrd");
cmd_linux = grub_register_command ("linux", grub_cmd_linux,
0, N_("Load Linux."));
cmd_initrd = grub_register_command ("initrd", grub_cmd_initrd,
0, N_("Load initrd."));
my_mod = mod;
}
GRUB_MOD_FINI(linux)
{
grub_rescue_unregister_command ("linux");
grub_rescue_unregister_command ("initrd");
grub_unregister_command (cmd_linux);
grub_unregister_command (cmd_initrd);
}

View file

@ -1,60 +0,0 @@
/* linux_normal.c - boot Linux */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2004,2007 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/>.
*/
#include <grub/normal.h>
#include <grub/dl.h>
#include <grub/machine/loader.h>
static const struct grub_arg_option options[] =
{
{0, 0, 0, 0, 0, 0}
};
static grub_err_t
grub_cmd_linux (struct grub_arg_list *state __attribute__ ((unused)),
int argc, char **args)
{
grub_rescue_cmd_linux (argc, args);
return GRUB_ERR_NONE;
}
static grub_err_t
grub_cmd_initrd (struct grub_arg_list *state __attribute__ ((unused)),
int argc, char **args)
{
grub_rescue_cmd_initrd (argc, args);
return GRUB_ERR_NONE;
}
GRUB_MOD_INIT(linux_normal)
{
(void) mod;
grub_register_command ("linux", grub_cmd_linux, GRUB_COMMAND_FLAG_BOTH,
"linux [KERNELARGS...]",
"Loads linux", options);
grub_register_command ("initrd", grub_cmd_initrd, GRUB_COMMAND_FLAG_BOTH,
"initrd FILE",
"Loads initrd", options);
}
GRUB_MOD_FINI(linux_normal)
{
grub_unregister_command ("linux");
grub_unregister_command ("initrd");
}

View file

@ -1,125 +0,0 @@
/* multiboot.c - boot a multiboot 2 OS image. */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2007 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/>.
*/
#include <multiboot2.h>
#include <grub/loader.h>
#include <grub/ieee1275/ieee1275.h>
#include <grub/multiboot2.h>
#include <grub/err.h>
#include <grub/elf.h>
#include <grub/misc.h>
#include <grub/mm.h>
#include <grub/machine/kernel.h>
typedef void (*kernel_entry_t) (unsigned long, void *, int (void *),
unsigned long, unsigned long);
/* Claim the memory occupied by the multiboot kernel. */
grub_err_t
grub_mb2_arch_elf32_hook (Elf32_Phdr *phdr, UNUSED grub_addr_t *addr)
{
int rc;
rc = grub_claimmap (phdr->p_paddr, phdr->p_memsz);
if (rc)
return grub_error(GRUB_ERR_OUT_OF_MEMORY, "Couldn't claim %x - %x",
phdr->p_paddr, phdr->p_paddr + phdr->p_memsz);
grub_dprintf ("loader", "Loading segment at 0x%x - 0x%x\n", phdr->p_paddr,
phdr->p_paddr + phdr->p_memsz);
return GRUB_ERR_NONE;
}
/* Claim the memory occupied by the multiboot kernel. */
grub_err_t
grub_mb2_arch_elf64_hook (Elf64_Phdr *phdr, UNUSED grub_addr_t *addr)
{
int rc;
rc = grub_claimmap (phdr->p_paddr, phdr->p_memsz);
if (rc)
return grub_error(GRUB_ERR_OUT_OF_MEMORY, "Couldn't claim 0x%lx - 0x%lx",
phdr->p_paddr, phdr->p_paddr + phdr->p_memsz);
grub_dprintf ("loader", "Loading segment at 0x%lx - 0x%lx\n",
(unsigned long) phdr->p_paddr,
(unsigned long) (phdr->p_paddr + phdr->p_memsz));
return GRUB_ERR_NONE;
}
grub_err_t
grub_mb2_arch_module_alloc (grub_size_t size, grub_addr_t *addr)
{
int rc;
/* XXX Will need to map on some firmwares. */
rc = grub_ieee1275_claim (0, size, MULTIBOOT2_MOD_ALIGN, addr);
if (rc)
return grub_error (GRUB_ERR_OUT_OF_MEMORY,
"Firmware couldn't allocate memory (size 0x%lx)", size);
return GRUB_ERR_NONE;
}
grub_err_t
grub_mb2_arch_module_free (grub_addr_t addr, grub_size_t size)
{
grub_ieee1275_release (addr, size);
return GRUB_ERR_NONE;
}
grub_err_t
grub_mb2_tags_arch_create (void)
{
/* Nothing special. */
return GRUB_ERR_NONE;
}
/* Release the memory we claimed from Open Firmware above. */
void
grub_mb2_arch_unload (struct multiboot_tag_header *tags)
{
struct multiboot_tag_header *tag;
/* Free all module memory in the tag list. */
for_each_tag (tag, tags)
{
if (tag->key == MULTIBOOT2_TAG_MODULE)
{
struct multiboot_tag_module *module =
(struct multiboot_tag_module *) tag;
grub_ieee1275_release (module->addr, module->size);
}
}
}
void
grub_mb2_arch_boot (grub_addr_t entry_addr, void *tags)
{
kernel_entry_t entry = (kernel_entry_t) entry_addr;
#if defined(__powerpc__)
entry (MULTIBOOT2_BOOTLOADER_MAGIC, tags, grub_ieee1275_entry_fn, 0, 0);
#elif defined(__i386__)
grub_multiboot2_real_boot (entry, tags);
#else
#error
#endif
}

View file

@ -0,0 +1,530 @@
/* linux.c - boot Linux */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2003, 2004, 2005, 2007, 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/>.
*/
#include <grub/elf.h>
#include <grub/elfload.h>
#include <grub/loader.h>
#include <grub/dl.h>
#include <grub/mm.h>
#include <grub/misc.h>
#include <grub/ieee1275/ieee1275.h>
#include <grub/machine/loader.h>
#include <grub/gzio.h>
#include <grub/command.h>
#include <grub/i18n.h>
static grub_dl_t my_mod;
static int loaded;
/* /virtual-memory/translations property layout */
struct grub_ieee1275_translation {
grub_uint64_t vaddr;
grub_uint64_t size;
grub_uint64_t data;
};
static struct grub_ieee1275_translation *of_trans;
static int of_num_trans;
static grub_addr_t phys_base;
static grub_addr_t grub_phys_start;
static grub_addr_t grub_phys_end;
static grub_addr_t initrd_addr;
static grub_addr_t initrd_paddr;
static grub_size_t initrd_size;
static Elf64_Addr linux_entry;
static grub_addr_t linux_addr;
static grub_addr_t linux_paddr;
static grub_size_t linux_size;
static char *linux_args;
typedef void (*kernel_entry_t) (unsigned long, unsigned long,
unsigned long, unsigned long, int (void *));
struct linux_bootstr_info {
int len, valid;
char buf[];
};
struct linux_hdrs {
/* All HdrS versions support these fields. */
unsigned int start_insns[2];
char magic[4]; /* "HdrS" */
unsigned int linux_kernel_version; /* LINUX_VERSION_CODE */
unsigned short hdrs_version;
unsigned short root_flags;
unsigned short root_dev;
unsigned short ram_flags;
unsigned int __deprecated_ramdisk_image;
unsigned int ramdisk_size;
/* HdrS versions 0x0201 and higher only */
char *reboot_command;
/* HdrS versions 0x0202 and higher only */
struct linux_bootstr_info *bootstr_info;
/* HdrS versions 0x0301 and higher only */
unsigned long ramdisk_image;
};
static grub_err_t
grub_linux_boot (void)
{
struct linux_bootstr_info *bp;
kernel_entry_t linuxmain;
struct linux_hdrs *hp;
grub_addr_t addr;
hp = (struct linux_hdrs *) linux_addr;
/* Any pointer we dereference in the kernel image must be relocated
to where we actually loaded the kernel. */
addr = (grub_addr_t) hp->bootstr_info;
addr += (linux_addr - linux_entry);
bp = (struct linux_bootstr_info *) addr;
/* Set the command line arguments, unless the kernel has been
built with a fixed CONFIG_CMDLINE. */
if (!bp->valid)
{
int len = grub_strlen (linux_args) + 1;
if (bp->len < len)
len = bp->len;
memcpy(bp->buf, linux_args, len);
bp->buf[len-1] = '\0';
bp->valid = 1;
}
if (initrd_addr)
{
/* The kernel expects the physical address, adjusted relative
to the lowest address advertised in "/memory"'s available
property.
The history of this is that back when the kernel only supported
specifying a 32-bit ramdisk address, this was the way to still
be able to specify the ramdisk physical address even if memory
started at some place above 4GB.
The magic 0x400000 is KERNBASE, I have no idea why SILO adds
that term into the address, but it does and thus we have to do
it too as this is what the kernel expects. */
hp->ramdisk_image = initrd_paddr - phys_base + 0x400000;
hp->ramdisk_size = initrd_size;
}
grub_dprintf ("loader", "Entry point: 0x%lx\n", linux_addr);
grub_dprintf ("loader", "Initrd at: 0x%lx, size 0x%lx\n", initrd_addr,
initrd_size);
grub_dprintf ("loader", "Boot arguments: %s\n", linux_args);
grub_dprintf ("loader", "Jumping to Linux...\n");
/* Boot the kernel. */
linuxmain = (kernel_entry_t) linux_addr;
linuxmain (0, 0, 0, 0, grub_ieee1275_entry_fn);
return GRUB_ERR_NONE;
}
static grub_err_t
grub_linux_release_mem (void)
{
grub_free (linux_args);
linux_args = 0;
linux_addr = 0;
initrd_addr = 0;
return GRUB_ERR_NONE;
}
static grub_err_t
grub_linux_unload (void)
{
grub_err_t err;
err = grub_linux_release_mem ();
grub_dl_unref (my_mod);
loaded = 0;
return err;
}
#define FOUR_MB (4 * 1024 * 1024)
static grub_addr_t
align_addr(grub_addr_t val, grub_addr_t align)
{
return (val + (align - 1)) & ~(align - 1);
}
static grub_addr_t
alloc_phys (grub_addr_t size)
{
grub_addr_t ret = (grub_addr_t) -1;
auto int NESTED_FUNC_ATTR choose (grub_uint64_t addr, grub_uint64_t len __attribute__((unused)), grub_uint32_t type);
int NESTED_FUNC_ATTR choose (grub_uint64_t addr, grub_uint64_t len __attribute__((unused)), grub_uint32_t type)
{
grub_addr_t end = addr + len;
if (type != 1)
return 0;
addr = align_addr (addr, FOUR_MB);
if (addr >= end)
return 0;
if (addr >= grub_phys_start && addr < grub_phys_end)
{
addr = align_addr (grub_phys_end, FOUR_MB);
if (addr >= end)
return 0;
}
if ((addr + size) >= grub_phys_start
&& (addr + size) < grub_phys_end)
{
addr = align_addr (grub_phys_end, FOUR_MB);
if (addr >= end)
return 0;
}
if (loaded)
{
grub_addr_t linux_end = align_addr (linux_paddr + linux_size, FOUR_MB);
if (addr >= linux_paddr && addr < linux_end)
{
addr = linux_end;
if (addr >= end)
return 0;
}
if ((addr + size) >= linux_paddr
&& (addr + size) < linux_end)
{
addr = linux_end;
if (addr >= end)
return 0;
}
}
ret = addr;
return 1;
}
grub_machine_mmap_iterate (choose);
return ret;
}
static grub_err_t
grub_linux_load64 (grub_elf_t elf)
{
grub_addr_t off, paddr, base;
int ret;
linux_entry = elf->ehdr.ehdr64.e_entry;
linux_addr = 0x40004000;
off = 0x4000;
linux_size = grub_elf64_size (elf);
if (linux_size == 0)
return grub_errno;
grub_dprintf ("loader", "Attempting to claim at 0x%lx, size 0x%lx.\n",
linux_addr, linux_size);
paddr = alloc_phys (linux_size + off);
if (paddr == (grub_addr_t) -1)
return grub_error (GRUB_ERR_OUT_OF_MEMORY,
"couldn't allocate physical memory");
ret = grub_ieee1275_map_physical (paddr, linux_addr - off,
linux_size + off, IEEE1275_MAP_DEFAULT);
if (ret)
return grub_error (GRUB_ERR_OUT_OF_MEMORY,
"couldn't map physical memory");
grub_dprintf ("loader", "Loading Linux at vaddr 0x%lx, paddr 0x%lx, size 0x%lx\n",
linux_addr, paddr, linux_size);
linux_paddr = paddr;
base = linux_entry - off;
/* Now load the segments into the area we claimed. */
auto grub_err_t offset_phdr (Elf64_Phdr *phdr, grub_addr_t *addr, int *do_load);
grub_err_t offset_phdr (Elf64_Phdr *phdr, grub_addr_t *addr, int *do_load)
{
if (phdr->p_type != PT_LOAD)
{
*do_load = 0;
return 0;
}
*do_load = 1;
/* Adjust the program load address to linux_addr. */
*addr = (phdr->p_paddr - base) + (linux_addr - off);
return 0;
}
return grub_elf64_load (elf, offset_phdr, 0, 0);
}
static grub_err_t
grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
int argc, char *argv[])
{
grub_file_t file = 0;
grub_elf_t elf = 0;
int i;
int size;
char *dest;
grub_dl_ref (my_mod);
if (argc == 0)
{
grub_error (GRUB_ERR_BAD_ARGUMENT, "no kernel specified");
goto out;
}
file = grub_gzfile_open (argv[0], 1);
if (!file)
goto out;
elf = grub_elf_file (file);
if (! elf)
goto out;
if (elf->ehdr.ehdr32.e_type != ET_EXEC)
{
grub_error (GRUB_ERR_UNKNOWN_OS,
"this ELF file is not of the right type");
goto out;
}
/* Release the previously used memory. */
grub_loader_unset ();
if (grub_elf_is_elf64 (elf))
grub_linux_load64 (elf);
else
{
grub_error (GRUB_ERR_BAD_FILE_TYPE, "unknown ELF class");
goto out;
}
size = sizeof ("BOOT_IMAGE=") + grub_strlen (argv[0]);
for (i = 0; i < argc; i++)
size += grub_strlen (argv[i]) + 1;
linux_args = grub_malloc (size);
if (! linux_args)
goto out;
/* Specify the boot file. */
dest = grub_stpcpy (linux_args, "BOOT_IMAGE=");
dest = grub_stpcpy (dest, argv[0]);
for (i = 1; i < argc; i++)
{
*dest++ = ' ';
dest = grub_stpcpy (dest, argv[i]);
}
out:
if (elf)
grub_elf_close (elf);
else if (file)
grub_file_close (file);
if (grub_errno != GRUB_ERR_NONE)
{
grub_linux_release_mem ();
grub_dl_unref (my_mod);
loaded = 0;
}
else
{
grub_loader_set (grub_linux_boot, grub_linux_unload, 1);
initrd_addr = 0;
loaded = 1;
}
return grub_errno;
}
static grub_err_t
grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
int argc, char *argv[])
{
grub_file_t file = 0;
grub_ssize_t size;
grub_addr_t paddr;
grub_addr_t addr;
int ret;
if (argc == 0)
{
grub_error (GRUB_ERR_BAD_ARGUMENT, "no initrd specified");
goto fail;
}
if (!loaded)
{
grub_error (GRUB_ERR_BAD_ARGUMENT, "you need to load the kernel first");
goto fail;
}
file = grub_file_open (argv[0]);
if (! file)
goto fail;
addr = 0x60000000;
size = grub_file_size (file);
paddr = alloc_phys (size);
if (paddr == (grub_addr_t) -1)
{
grub_error (GRUB_ERR_OUT_OF_MEMORY,
"couldn't allocate physical memory");
goto fail;
}
ret = grub_ieee1275_map_physical (paddr, addr, size, IEEE1275_MAP_DEFAULT);
if (ret)
{
grub_error (GRUB_ERR_OUT_OF_MEMORY,
"couldn't map physical memory");
goto fail;
}
grub_dprintf ("loader", "Loading initrd at vaddr 0x%lx, paddr 0x%lx, size 0x%lx\n",
addr, paddr, size);
if (grub_file_read (file, (void *) addr, size) != size)
{
grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file");
goto fail;
}
initrd_addr = addr;
initrd_paddr = paddr;
initrd_size = size;
fail:
if (file)
grub_file_close (file);
return grub_errno;
}
static void
determine_phys_base (void)
{
auto int NESTED_FUNC_ATTR get_physbase (grub_uint64_t addr, grub_uint64_t len __attribute__((unused)), grub_uint32_t type);
int NESTED_FUNC_ATTR get_physbase (grub_uint64_t addr, grub_uint64_t len __attribute__((unused)), grub_uint32_t type)
{
if (type != 1)
return 0;
if (addr < phys_base)
phys_base = addr;
return 0;
}
phys_base = ~(grub_uint64_t) 0;
grub_machine_mmap_iterate (get_physbase);
}
static void
fetch_translations (void)
{
grub_ieee1275_phandle_t node;
grub_ssize_t actual;
int i;
if (grub_ieee1275_finddevice ("/virtual-memory", &node))
{
grub_printf ("Cannot find /virtual-memory node.\n");
return;
}
if (grub_ieee1275_get_property_length (node, "translations", &actual))
{
grub_printf ("Cannot find /virtual-memory/translations size.\n");
return;
}
of_trans = grub_malloc (actual);
if (!of_trans)
{
grub_printf ("Cannot allocate translations buffer.\n");
return;
}
if (grub_ieee1275_get_property (node, "translations", of_trans, actual, &actual))
{
grub_printf ("Cannot fetch /virtual-memory/translations property.\n");
return;
}
of_num_trans = actual / sizeof(struct grub_ieee1275_translation);
for (i = 0; i < of_num_trans; i++)
{
struct grub_ieee1275_translation *p = &of_trans[i];
if (p->vaddr == 0x2000)
{
grub_addr_t phys, tte = p->data;
phys = tte & ~(0xff00000000001fffULL);
grub_phys_start = phys;
grub_phys_end = grub_phys_start + p->size;
grub_dprintf ("loader", "Grub lives at phys_start[%lx] phys_end[%lx]\n",
(unsigned long) grub_phys_start,
(unsigned long) grub_phys_end);
break;
}
}
}
static grub_command_t cmd_linux, cmd_initrd;
GRUB_MOD_INIT(linux)
{
determine_phys_base ();
fetch_translations ();
cmd_linux = grub_register_command ("linux", grub_cmd_linux,
0, N_("Load Linux."));
cmd_initrd = grub_register_command ("initrd", grub_cmd_initrd,
0, N_("Load initrd."));
my_mod = mod;
}
GRUB_MOD_FINI(linux)
{
grub_unregister_command (cmd_linux);
grub_unregister_command (cmd_initrd);
}

1448
loader/xnu.c Normal file

File diff suppressed because it is too large Load diff

145
loader/xnu_resume.c Normal file
View file

@ -0,0 +1,145 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 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/>.
*/
#include <grub/normal.h>
#include <grub/dl.h>
#include <grub/file.h>
#include <grub/disk.h>
#include <grub/misc.h>
#include <grub/xnu.h>
#include <grub/cpu/xnu.h>
#include <grub/mm.h>
#include <grub/loader.h>
static void *grub_xnu_hibernate_image;
static grub_err_t
grub_xnu_resume_unload (void)
{
/* Free loaded image */
if (grub_xnu_hibernate_image)
grub_free (grub_xnu_hibernate_image);
grub_xnu_hibernate_image = 0;
grub_xnu_unlock ();
return GRUB_ERR_NONE;
}
grub_err_t
grub_xnu_resume (char *imagename)
{
grub_file_t file;
grub_size_t total_header_size;
struct grub_xnu_hibernate_header hibhead;
grub_uint8_t *buf;
grub_uint32_t codedest;
grub_uint32_t codesize;
file = grub_file_open (imagename);
if (! file)
return 0;
/* Read the header. */
if (grub_file_read (file, &hibhead, sizeof (hibhead))
!=sizeof (hibhead))
{
grub_file_close (file);
return grub_error (GRUB_ERR_READ_ERROR,
"cannot read the hibernate header");
}
/* Check the header. */
if (hibhead.magic != GRUB_XNU_HIBERNATE_MAGIC)
{
grub_file_close (file);
return grub_error (GRUB_ERR_BAD_OS,
"hibernate header has incorrect magic number");
}
if (hibhead.encoffset)
{
grub_file_close (file);
return grub_error (GRUB_ERR_BAD_OS,
"encrypted images aren't supported yet");
}
codedest = hibhead.launchcode_target_page;
codedest *= GRUB_XNU_PAGESIZE;
codesize = hibhead.launchcode_numpages;
codesize *= GRUB_XNU_PAGESIZE;
/* FIXME: check that codedest..codedest+codesize is available. */
/* Calculate total size before pages to copy. */
total_header_size = hibhead.extmapsize + sizeof (hibhead);
/* Unload image if any. */
if (grub_xnu_hibernate_image)
grub_free (grub_xnu_hibernate_image);
/* Try to allocate necessary space.
FIXME: mm isn't good enough yet to handle huge allocations.
*/
grub_xnu_hibernate_image = buf = XNU_RELOCATOR (alloc) (hibhead.image_size
+ codesize
+ GRUB_XNU_PAGESIZE);
if (! buf)
{
grub_file_close (file);
return grub_errno;
}
/* Read code part. */
if (grub_file_seek (file, total_header_size) == (grub_off_t) -1
|| grub_file_read (file, buf, codesize)
!= (grub_ssize_t) codesize)
{
grub_file_close (file);
return grub_error (GRUB_ERR_READ_ERROR, "cannot read resume image");
}
/* Read image. */
if (grub_file_seek (file, 0) == (grub_off_t) -1
|| grub_file_read (file, buf + codesize + GRUB_XNU_PAGESIZE,
hibhead.image_size)
!= (grub_ssize_t) hibhead.image_size)
{
grub_file_close (file);
return grub_error (GRUB_ERR_READ_ERROR, "cannot read resume image");
}
grub_file_close (file);
/* Setup variables needed by asm helper. */
grub_xnu_heap_will_be_at = codedest;
grub_xnu_heap_start = buf;
grub_xnu_heap_size = codesize + GRUB_XNU_PAGESIZE + hibhead.image_size;
grub_xnu_stack = (codedest + hibhead.stack);
grub_xnu_entry_point = (codedest + hibhead.entry_point);
grub_xnu_arg1 = codedest + codesize + GRUB_XNU_PAGESIZE;
grub_dprintf ("xnu", "entry point 0x%x\n", codedest + hibhead.entry_point);
grub_dprintf ("xnu", "image at 0x%x\n",
codedest + codesize + GRUB_XNU_PAGESIZE);
/* We're ready now. */
grub_loader_set (grub_xnu_boot_resume,
grub_xnu_resume_unload, 0);
/* Prevent module from unloading. */
grub_xnu_lock ();
return GRUB_ERR_NONE;
}