2009-06-21 Vladimir Serbinenko <phcoder@gmail.com>
Load BSD ELF modules * conf/i386-pc.rmk (bsd_mod_SOURCES): Add loader/i386/bsd32.c and loader/i386/bsd64.c * include/grub/i386/bsd.h (FREEBSD_MODTYPE_MODULE): Remove (FREEBSD_MODTYPE_ELF_MODULE): New definition (FREEBSD_MODTYPE_ELF_MODULE_OBJ): Likewise (grub_freebsd_load_elfmodule32): New declaration (grub_freebsd_load_elfmoduleobj64): Likewise (grub_freebsd_load_elf_meta32): Likewise (grub_freebsd_load_elf_meta64): Likewise (grub_freebsd_add_meta): Likewise (grub_freebsd_add_meta_module): Likewise * loader/i386/bsd.c (grub_freebsd_add_meta): Make global (grub_freebsd_add_meta_module): Likewise and move module-specific parts to grub_cmd_freebsd and grub_cmd_freebsd_module (grub_cmd_freebsd): Add elf-kernel specific parts based on grub_freebsd_add_meta_module (grub_cmd_freebsd_module): Add type parsing moved from grub_freebsd_add_meta_module (grub_cmd_freebsd_module_elf): New function (cmd_freebsd_module_elf): New variable (GRUB_MOD_INIT): Register freebsd_module_elf * loader/i386/bsd32.c: New file * loader/i386/bsd64.c: Likewise * loader/i386/bsdXX.c: Likewise * kern/elf.c (grub_elf32_load): Let hook decide which pheaders to load (grub_elf64_load): Likewise * include/grub/elfload.h (grub_elf32_load_hook_t): New parameter do_load All users updated (grub_elf64_load_hook_t): Likewise
This commit is contained in:
parent
0db15301d1
commit
3f3ec72b38
14 changed files with 613 additions and 68 deletions
34
ChangeLog
34
ChangeLog
|
@ -1,3 +1,37 @@
|
|||
2009-06-21 Vladimir Serbinenko <phcoder@gmail.com>
|
||||
|
||||
Load BSD ELF modules
|
||||
|
||||
* conf/i386-pc.rmk (bsd_mod_SOURCES): Add loader/i386/bsd32.c
|
||||
and loader/i386/bsd64.c
|
||||
* include/grub/i386/bsd.h (FREEBSD_MODTYPE_MODULE): Remove
|
||||
(FREEBSD_MODTYPE_ELF_MODULE): New definition
|
||||
(FREEBSD_MODTYPE_ELF_MODULE_OBJ): Likewise
|
||||
(grub_freebsd_load_elfmodule32): New declaration
|
||||
(grub_freebsd_load_elfmoduleobj64): Likewise
|
||||
(grub_freebsd_load_elf_meta32): Likewise
|
||||
(grub_freebsd_load_elf_meta64): Likewise
|
||||
(grub_freebsd_add_meta): Likewise
|
||||
(grub_freebsd_add_meta_module): Likewise
|
||||
* loader/i386/bsd.c (grub_freebsd_add_meta): Make global
|
||||
(grub_freebsd_add_meta_module): Likewise and move module-specific
|
||||
parts to grub_cmd_freebsd and grub_cmd_freebsd_module
|
||||
(grub_cmd_freebsd): Add elf-kernel specific parts
|
||||
based on grub_freebsd_add_meta_module
|
||||
(grub_cmd_freebsd_module): Add type parsing moved from
|
||||
grub_freebsd_add_meta_module
|
||||
(grub_cmd_freebsd_module_elf): New function
|
||||
(cmd_freebsd_module_elf): New variable
|
||||
(GRUB_MOD_INIT): Register freebsd_module_elf
|
||||
* loader/i386/bsd32.c: New file
|
||||
* loader/i386/bsd64.c: Likewise
|
||||
* loader/i386/bsdXX.c: Likewise
|
||||
* kern/elf.c (grub_elf32_load): Let hook decide which pheaders to load
|
||||
(grub_elf64_load): Likewise
|
||||
* include/grub/elfload.h (grub_elf32_load_hook_t): New parameter do_load
|
||||
All users updated
|
||||
(grub_elf64_load_hook_t): Likewise
|
||||
|
||||
2009-06-21 Colin Watson <cjwatson@ubuntu.com>
|
||||
|
||||
* util/grub-mkconfig.in (GRUB_DISABLE_LINUX_RECOVERY): Export
|
||||
|
|
|
@ -329,7 +329,7 @@ aout_mod_CFLAGS = $(COMMON_CFLAGS)
|
|||
aout_mod_LDFLAGS = $(COMMON_LDFLAGS)
|
||||
|
||||
# For bsd.mod
|
||||
bsd_mod_SOURCES = loader/i386/bsd.c loader/i386/bsd_helper.S loader/i386/bsd_trampoline.S
|
||||
bsd_mod_SOURCES = loader/i386/bsd.c loader/i386/bsd32.c loader/i386/bsd64.c loader/i386/bsd_helper.S loader/i386/bsd_trampoline.S
|
||||
bsd_mod_CFLAGS = $(COMMON_CFLAGS)
|
||||
bsd_mod_LDFLAGS = $(COMMON_LDFLAGS)
|
||||
bsd_mod_ASFLAGS = $(COMMON_ASFLAGS)
|
||||
|
|
|
@ -37,9 +37,9 @@ struct grub_elf_file
|
|||
typedef struct grub_elf_file *grub_elf_t;
|
||||
|
||||
typedef grub_err_t (*grub_elf32_load_hook_t)
|
||||
(Elf32_Phdr *phdr, grub_addr_t *addr);
|
||||
(Elf32_Phdr *phdr, grub_addr_t *addr, int *load);
|
||||
typedef grub_err_t (*grub_elf64_load_hook_t)
|
||||
(Elf64_Phdr *phdr, grub_addr_t *addr);
|
||||
(Elf64_Phdr *phdr, grub_addr_t *addr, int *load);
|
||||
|
||||
grub_elf_t grub_elf_open (const char *);
|
||||
grub_elf_t grub_elf_file (grub_file_t);
|
||||
|
|
|
@ -86,7 +86,8 @@
|
|||
|
||||
#define FREEBSD_MODTYPE_KERNEL "elf kernel"
|
||||
#define FREEBSD_MODTYPE_KERNEL64 "elf64 kernel"
|
||||
#define FREEBSD_MODTYPE_MODULE "elf module"
|
||||
#define FREEBSD_MODTYPE_ELF_MODULE "elf module"
|
||||
#define FREEBSD_MODTYPE_ELF_MODULE_OBJ "elf obj module"
|
||||
#define FREEBSD_MODTYPE_RAW "raw"
|
||||
|
||||
struct grub_freebsd_bootinfo
|
||||
|
@ -229,6 +230,21 @@ struct grub_netbsd_btinfo_bootdisk
|
|||
|
||||
void grub_unix_real_boot (grub_addr_t entry, ...)
|
||||
__attribute__ ((cdecl,noreturn));
|
||||
grub_err_t grub_freebsd_load_elfmodule32 (grub_file_t file, int argc,
|
||||
char *argv[], grub_addr_t *kern_end);
|
||||
grub_err_t grub_freebsd_load_elfmodule_obj64 (grub_file_t file, int argc,
|
||||
char *argv[],
|
||||
grub_addr_t *kern_end);
|
||||
grub_err_t grub_freebsd_load_elf_meta32 (grub_file_t file,
|
||||
grub_addr_t *kern_end);
|
||||
grub_err_t grub_freebsd_load_elf_meta64 (grub_file_t file,
|
||||
grub_addr_t *kern_end);
|
||||
|
||||
grub_err_t grub_freebsd_add_meta (grub_uint32_t type, void *data,
|
||||
grub_uint32_t len);
|
||||
grub_err_t grub_freebsd_add_meta_module (char *filename, char *type,
|
||||
int argc, char **argv,
|
||||
grub_addr_t addr, grub_uint32_t size);
|
||||
|
||||
extern grub_uint8_t grub_bsd64_trampoline_start, grub_bsd64_trampoline_end;
|
||||
extern grub_uint32_t grub_bsd64_trampoline_selfjump;
|
||||
|
|
|
@ -45,10 +45,10 @@ void
|
|||
grub_mb2_arch_unload (struct multiboot_tag_header *tags);
|
||||
|
||||
grub_err_t
|
||||
grub_mb2_arch_elf32_hook (Elf32_Phdr *phdr, grub_addr_t *addr);
|
||||
grub_mb2_arch_elf32_hook (Elf32_Phdr *phdr, grub_addr_t *addr, int *do_load);
|
||||
|
||||
grub_err_t
|
||||
grub_mb2_arch_elf64_hook (Elf64_Phdr *phdr, grub_addr_t *addr);
|
||||
grub_mb2_arch_elf64_hook (Elf64_Phdr *phdr, grub_addr_t *addr, int *do_load);
|
||||
|
||||
grub_err_t
|
||||
grub_mb2_arch_module_alloc (grub_size_t size, grub_addr_t *addr);
|
||||
|
|
18
kern/elf.c
18
kern/elf.c
|
@ -228,14 +228,15 @@ grub_elf32_load (grub_elf_t _elf, grub_elf32_load_hook_t _load_hook,
|
|||
{
|
||||
grub_elf32_load_hook_t load_hook = (grub_elf32_load_hook_t) hook;
|
||||
grub_addr_t load_addr;
|
||||
|
||||
if (phdr->p_type != PT_LOAD)
|
||||
return 0;
|
||||
int do_load = 1;
|
||||
|
||||
load_addr = phdr->p_paddr;
|
||||
if (load_hook && load_hook (phdr, &load_addr))
|
||||
if (load_hook && load_hook (phdr, &load_addr, &do_load))
|
||||
return 1;
|
||||
|
||||
if (! do_load)
|
||||
return 0;
|
||||
|
||||
if (load_addr < load_base)
|
||||
load_base = load_addr;
|
||||
|
||||
|
@ -407,14 +408,15 @@ grub_elf64_load (grub_elf_t _elf, grub_elf64_load_hook_t _load_hook,
|
|||
{
|
||||
grub_elf64_load_hook_t load_hook = (grub_elf64_load_hook_t) hook;
|
||||
grub_addr_t load_addr;
|
||||
|
||||
if (phdr->p_type != PT_LOAD)
|
||||
return 0;
|
||||
int do_load = 1;
|
||||
|
||||
load_addr = phdr->p_paddr;
|
||||
if (load_hook && load_hook (phdr, &load_addr))
|
||||
if (load_hook && load_hook (phdr, &load_addr, &do_load))
|
||||
return 1;
|
||||
|
||||
if (! do_load)
|
||||
return 0;
|
||||
|
||||
if (load_addr < load_base)
|
||||
load_base = load_addr;
|
||||
|
||||
|
|
|
@ -116,7 +116,7 @@ grub_bsd_get_device (grub_uint32_t * biosdev,
|
|||
grub_device_close (dev);
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_err_t
|
||||
grub_freebsd_add_meta (grub_uint32_t type, void *data, grub_uint32_t len)
|
||||
{
|
||||
if (mod_buf_max < mod_buf_len + len + 8)
|
||||
|
@ -261,36 +261,21 @@ grub_freebsd_add_mmap (void)
|
|||
return grub_errno;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_freebsd_add_meta_module (int is_kern, int argc, char **argv,
|
||||
grub_err_t
|
||||
grub_freebsd_add_meta_module (char *filename, char *type, int argc, char **argv,
|
||||
grub_addr_t addr, grub_uint32_t size)
|
||||
{
|
||||
char *name, *type;
|
||||
|
||||
name = grub_strrchr (argv[0], '/');
|
||||
char *name;
|
||||
name = grub_strrchr (filename, '/');
|
||||
if (name)
|
||||
name++;
|
||||
else
|
||||
name = argv[0];
|
||||
name = filename;
|
||||
|
||||
if (grub_freebsd_add_meta (FREEBSD_MODINFO_NAME, name,
|
||||
grub_strlen (name) + 1))
|
||||
return grub_errno;
|
||||
|
||||
argc--;
|
||||
argv++;
|
||||
|
||||
if ((argc) && (!grub_memcmp (argv[0], "type=", 5)))
|
||||
{
|
||||
type = &argv[0][5];
|
||||
argc--;
|
||||
argv++;
|
||||
}
|
||||
else
|
||||
type = ((is_kern) ?
|
||||
((is_64bit) ? FREEBSD_MODTYPE_KERNEL64 : FREEBSD_MODTYPE_KERNEL)
|
||||
: FREEBSD_MODTYPE_RAW);
|
||||
|
||||
if (is_64bit)
|
||||
{
|
||||
grub_uint64_t addr64 = addr, size64 = size;
|
||||
|
@ -341,23 +326,6 @@ grub_freebsd_add_meta_module (int is_kern, int argc, char **argv,
|
|||
}
|
||||
}
|
||||
|
||||
if (is_kern)
|
||||
{
|
||||
int len = (is_64bit) ? 8 : 4;
|
||||
grub_uint64_t data = 0;
|
||||
|
||||
if ((grub_freebsd_add_meta (FREEBSD_MODINFO_METADATA |
|
||||
FREEBSD_MODINFOMD_HOWTO, &data, 4)) ||
|
||||
(grub_freebsd_add_meta (FREEBSD_MODINFO_METADATA |
|
||||
FREEBSD_MODINFOMD_ENVP, &data, len)) ||
|
||||
(grub_freebsd_add_meta (FREEBSD_MODINFO_METADATA |
|
||||
FREEBSD_MODINFOMD_KERNEND, &data, len)))
|
||||
return grub_errno;
|
||||
kern_end_mdofs = mod_buf_len - len;
|
||||
|
||||
return grub_freebsd_add_mmap ();
|
||||
}
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
|
@ -688,10 +656,18 @@ grub_bsd_load_aout (grub_file_t file)
|
|||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_bsd_elf32_hook (Elf32_Phdr * phdr, grub_addr_t * addr)
|
||||
grub_bsd_elf32_hook (Elf32_Phdr * phdr, grub_addr_t * addr, int *do_load)
|
||||
{
|
||||
Elf32_Addr paddr;
|
||||
|
||||
if (phdr->p_type != PT_LOAD
|
||||
&& phdr->p_type != PT_DYNAMIC)
|
||||
{
|
||||
*do_load = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
*do_load = 1;
|
||||
phdr->p_paddr &= 0xFFFFFF;
|
||||
paddr = phdr->p_paddr;
|
||||
|
||||
|
@ -712,10 +688,18 @@ grub_bsd_elf32_hook (Elf32_Phdr * phdr, grub_addr_t * addr)
|
|||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_bsd_elf64_hook (Elf64_Phdr * phdr, grub_addr_t * addr)
|
||||
grub_bsd_elf64_hook (Elf64_Phdr * phdr, grub_addr_t * addr, int *do_load)
|
||||
{
|
||||
Elf64_Addr paddr;
|
||||
|
||||
if (phdr->p_type != PT_LOAD
|
||||
&& phdr->p_type != PT_DYNAMIC)
|
||||
{
|
||||
*do_load = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
*do_load = 1;
|
||||
paddr = phdr->p_paddr & 0xffffff;
|
||||
|
||||
if ((paddr < grub_os_area_addr)
|
||||
|
@ -838,10 +822,54 @@ grub_cmd_freebsd (grub_command_t cmd __attribute__ ((unused)),
|
|||
if (grub_bsd_load (argc, argv) == GRUB_ERR_NONE)
|
||||
{
|
||||
kern_end = ALIGN_PAGE (kern_end);
|
||||
if ((is_elf_kernel) &&
|
||||
(grub_freebsd_add_meta_module (1, argc, argv, kern_start,
|
||||
kern_end - kern_start)))
|
||||
return grub_errno;
|
||||
if (is_elf_kernel)
|
||||
{
|
||||
grub_err_t err;
|
||||
grub_uint64_t data = 0;
|
||||
grub_file_t file;
|
||||
int len = is_64bit ? 8 : 4;
|
||||
|
||||
err = grub_freebsd_add_meta_module (argv[0], is_64bit
|
||||
? FREEBSD_MODTYPE_KERNEL64
|
||||
: FREEBSD_MODTYPE_KERNEL,
|
||||
argc - 1, argv + 1,
|
||||
kern_start,
|
||||
kern_end - kern_start);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
file = grub_gzfile_open (argv[0], 1);
|
||||
if (! file)
|
||||
return grub_errno;
|
||||
|
||||
if (is_64bit)
|
||||
err = grub_freebsd_load_elf_meta64 (file, &kern_end);
|
||||
else
|
||||
err = grub_freebsd_load_elf_meta32 (file, &kern_end);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = grub_freebsd_add_meta (FREEBSD_MODINFO_METADATA |
|
||||
FREEBSD_MODINFOMD_HOWTO, &data, 4);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = grub_freebsd_add_meta (FREEBSD_MODINFO_METADATA |
|
||||
FREEBSD_MODINFOMD_ENVP, &data, len);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = grub_freebsd_add_meta (FREEBSD_MODINFO_METADATA |
|
||||
FREEBSD_MODINFOMD_KERNEND, &data, len);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
kern_end_mdofs = mod_buf_len - len;
|
||||
|
||||
err = grub_freebsd_add_mmap ();
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
grub_loader_set (grub_freebsd_boot, grub_bsd_unload, 1);
|
||||
}
|
||||
|
||||
|
@ -969,6 +997,10 @@ grub_cmd_freebsd_module (grub_command_t cmd __attribute__ ((unused)),
|
|||
int argc, char *argv[])
|
||||
{
|
||||
grub_file_t file = 0;
|
||||
grub_err_t err;
|
||||
int modargc;
|
||||
char **modargv;
|
||||
char *type;
|
||||
|
||||
if (kernel_type != KERNEL_TYPE_FREEBSD)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT,
|
||||
|
@ -996,9 +1028,27 @@ grub_cmd_freebsd_module (grub_command_t cmd __attribute__ ((unused)),
|
|||
}
|
||||
|
||||
grub_file_read (file, (void *) kern_end, file->size);
|
||||
if ((!grub_errno) &&
|
||||
(!grub_freebsd_add_meta_module (0, argc, argv, kern_end, file->size)))
|
||||
kern_end = ALIGN_PAGE (kern_end + file->size);
|
||||
if (grub_errno)
|
||||
goto fail;
|
||||
|
||||
modargc = argc - 1;
|
||||
modargv = argv + 1;
|
||||
|
||||
if (modargc && (! grub_memcmp (modargv[0], "type=", 5)))
|
||||
{
|
||||
type = &modargv[0][5];
|
||||
modargc--;
|
||||
modargv++;
|
||||
}
|
||||
else
|
||||
type = FREEBSD_MODTYPE_RAW;
|
||||
|
||||
err = grub_freebsd_add_meta_module (argv[0], type, modargc, modargv,
|
||||
kern_end, file->size);
|
||||
if (err)
|
||||
goto fail;
|
||||
|
||||
kern_end = ALIGN_PAGE (kern_end + file->size);
|
||||
|
||||
fail:
|
||||
if (file)
|
||||
|
@ -1007,8 +1057,50 @@ fail:
|
|||
return grub_errno;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_cmd_freebsd_module_elf (grub_command_t cmd __attribute__ ((unused)),
|
||||
int argc, char *argv[])
|
||||
{
|
||||
grub_file_t file = 0;
|
||||
grub_err_t err;
|
||||
|
||||
if (kernel_type != KERNEL_TYPE_FREEBSD)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT,
|
||||
"only freebsd support module");
|
||||
|
||||
if (! is_elf_kernel)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT,
|
||||
"only elf kernel support module");
|
||||
|
||||
/* List the current modules if no parameter. */
|
||||
if (! argc)
|
||||
{
|
||||
grub_freebsd_list_modules ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
file = grub_gzfile_open (argv[0], 1);
|
||||
if (!file)
|
||||
return grub_errno;
|
||||
if (!file->size)
|
||||
{
|
||||
grub_file_close (file);
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
if (is_64bit)
|
||||
err = grub_freebsd_load_elfmodule_obj64 (file, argc, argv, &kern_end);
|
||||
else
|
||||
err = grub_freebsd_load_elfmodule32 (file, argc, argv, &kern_end);
|
||||
grub_file_close (file);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
static grub_command_t cmd_freebsd, cmd_openbsd, cmd_netbsd;
|
||||
static grub_command_t cmd_freebsd_loadenv, cmd_freebsd_module;
|
||||
static grub_command_t cmd_freebsd_module_elf;
|
||||
|
||||
GRUB_MOD_INIT (bsd)
|
||||
{
|
||||
|
@ -1027,6 +1119,9 @@ GRUB_MOD_INIT (bsd)
|
|||
cmd_freebsd_module =
|
||||
grub_register_command ("freebsd_module", grub_cmd_freebsd_module,
|
||||
0, "load freebsd module");
|
||||
cmd_freebsd_module_elf =
|
||||
grub_register_command ("freebsd_module_elf", grub_cmd_freebsd_module_elf,
|
||||
0, "load freebsd ELF module");
|
||||
|
||||
my_mod = mod;
|
||||
}
|
||||
|
@ -1039,6 +1134,7 @@ GRUB_MOD_FINI (bsd)
|
|||
|
||||
grub_unregister_command (cmd_freebsd_loadenv);
|
||||
grub_unregister_command (cmd_freebsd_module);
|
||||
grub_unregister_command (cmd_freebsd_module_elf);
|
||||
|
||||
if (mod_buf)
|
||||
{
|
||||
|
|
8
loader/i386/bsd32.c
Normal file
8
loader/i386/bsd32.c
Normal file
|
@ -0,0 +1,8 @@
|
|||
#define SUFFIX(x) x ## 32
|
||||
#define Elf_Ehdr Elf32_Ehdr
|
||||
#define Elf_Shdr Elf32_Shdr
|
||||
#define Elf_Sym Elf32_Sym
|
||||
#define OBJSYM 0
|
||||
#include <grub/types.h>
|
||||
typedef grub_uint32_t grub_freebsd_addr_t;
|
||||
#include "bsdXX.c"
|
8
loader/i386/bsd64.c
Normal file
8
loader/i386/bsd64.c
Normal file
|
@ -0,0 +1,8 @@
|
|||
#define SUFFIX(x) x ## 64
|
||||
#define Elf_Ehdr Elf64_Ehdr
|
||||
#define Elf_Shdr Elf64_Shdr
|
||||
#define Elf_Sym Elf64_Sym
|
||||
#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
329
loader/i386/bsdXX.c
Normal 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 (module + e.e_shoff), e.e_shoff,
|
||||
e.e_shnum * e.e_shentsize);
|
||||
if (curload < module + e.e_shoff + e.e_shnum * e.e_shentsize)
|
||||
curload = module + e.e_shoff + e.e_shnum * e.e_shentsize;
|
||||
|
||||
load (file, UINT_TO_PTR (module + e.e_phoff), e.e_phoff,
|
||||
e.e_phnum * e.e_phentsize);
|
||||
if (curload < module + e.e_phoff + e.e_phnum * e.e_phentsize)
|
||||
curload = module + e.e_phoff + 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;
|
||||
}
|
|
@ -27,10 +27,18 @@
|
|||
#include <grub/cpu/multiboot.h>
|
||||
|
||||
grub_err_t
|
||||
grub_mb2_arch_elf32_hook (Elf32_Phdr *phdr, UNUSED grub_addr_t *addr)
|
||||
grub_mb2_arch_elf32_hook (Elf32_Phdr *phdr, UNUSED grub_addr_t *addr,
|
||||
int *do_load)
|
||||
{
|
||||
Elf32_Addr paddr = phdr->p_paddr;
|
||||
|
||||
if (phdr->p_type != PT_LOAD)
|
||||
{
|
||||
*do_load = 0;
|
||||
return 0;
|
||||
}
|
||||
*do_load = 1;
|
||||
|
||||
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",
|
||||
|
@ -40,10 +48,18 @@ grub_mb2_arch_elf32_hook (Elf32_Phdr *phdr, UNUSED grub_addr_t *addr)
|
|||
}
|
||||
|
||||
grub_err_t
|
||||
grub_mb2_arch_elf64_hook (Elf64_Phdr *phdr, UNUSED grub_addr_t *addr)
|
||||
grub_mb2_arch_elf64_hook (Elf64_Phdr *phdr, UNUSED grub_addr_t *addr,
|
||||
int *do_load)
|
||||
{
|
||||
Elf64_Addr paddr = phdr->p_paddr;
|
||||
|
||||
if (phdr->p_type != PT_LOAD)
|
||||
{
|
||||
*do_load = 0;
|
||||
return 0;
|
||||
}
|
||||
*do_load = 1;
|
||||
|
||||
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",
|
||||
|
|
|
@ -36,10 +36,18 @@ typedef void (*kernel_entry_t) (unsigned long, void *, int (void *),
|
|||
|
||||
/* Claim the memory occupied by the multiboot kernel. */
|
||||
grub_err_t
|
||||
grub_mb2_arch_elf32_hook (Elf32_Phdr *phdr, UNUSED grub_addr_t *addr)
|
||||
grub_mb2_arch_elf32_hook (Elf32_Phdr *phdr, UNUSED grub_addr_t *addr,
|
||||
int *do_load)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (phdr->p_type != PT_LOAD)
|
||||
{
|
||||
*do_load = 0;
|
||||
return 0;
|
||||
}
|
||||
*do_load = 1;
|
||||
|
||||
rc = grub_claimmap (phdr->p_paddr, phdr->p_memsz);
|
||||
if (rc)
|
||||
return grub_error(GRUB_ERR_OUT_OF_MEMORY, "Couldn't claim %x - %x",
|
||||
|
@ -53,10 +61,18 @@ grub_mb2_arch_elf32_hook (Elf32_Phdr *phdr, UNUSED grub_addr_t *addr)
|
|||
|
||||
/* Claim the memory occupied by the multiboot kernel. */
|
||||
grub_err_t
|
||||
grub_mb2_arch_elf64_hook (Elf64_Phdr *phdr, UNUSED grub_addr_t *addr)
|
||||
grub_mb2_arch_elf64_hook (Elf64_Phdr *phdr, UNUSED grub_addr_t *addr,
|
||||
int *do_load)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (phdr->p_type != PT_LOAD)
|
||||
{
|
||||
*do_load = 0;
|
||||
return 0;
|
||||
}
|
||||
*do_load = 1;
|
||||
|
||||
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",
|
||||
|
|
|
@ -132,8 +132,15 @@ grub_linux_load32 (grub_elf_t elf)
|
|||
|
||||
/* 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)
|
||||
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;
|
||||
|
@ -175,8 +182,14 @@ grub_linux_load64 (grub_elf_t elf)
|
|||
|
||||
/* 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)
|
||||
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;
|
||||
|
|
|
@ -272,8 +272,15 @@ grub_linux_load64 (grub_elf_t elf)
|
|||
|
||||
/* 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)
|
||||
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;
|
||||
|
|
Loading…
Reference in a new issue