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:
phcoder 2009-06-21 15:48:10 +00:00
parent 0db15301d1
commit 3f3ec72b38
14 changed files with 613 additions and 68 deletions

View file

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