openbsd ramdisk support

This commit is contained in:
Vladimir 'phcoder' Serbinenko 2010-08-26 02:46:30 +02:00
parent 72d14db9ba
commit ecde61b490
3 changed files with 197 additions and 3 deletions

View file

@ -67,6 +67,7 @@ static grub_uint32_t bootflags;
static int is_elf_kernel, is_64bit;
static grub_uint32_t openbsd_root;
struct grub_relocator *relocator = NULL;
static struct grub_openbsd_ramdisk_descriptor openbsd_ramdisk;
struct bsd_tag
{
@ -1253,7 +1254,13 @@ grub_bsd_load_elf (grub_elf_t elf)
kern_chunk_src = get_virtual_current_address (ch);
return grub_elf32_load (elf, grub_bsd_elf32_hook, 0, 0);
err = grub_elf32_load (elf, grub_bsd_elf32_hook, 0, 0);
if (err)
return err;
if (kernel_type != KERNEL_TYPE_OPENBSD)
return GRUB_ERR_NONE;
return grub_openbsd_find_ramdisk32 (elf->file, kern_start,
kern_chunk_src, &openbsd_ramdisk);
}
else if (grub_elf_is_elf64 (elf))
{
@ -1290,7 +1297,13 @@ grub_bsd_load_elf (grub_elf_t elf)
kern_chunk_src = get_virtual_current_address (ch);
}
return grub_elf64_load (elf, grub_bsd_elf64_hook, 0, 0);
err = grub_elf64_load (elf, grub_bsd_elf64_hook, 0, 0);
if (err)
return err;
if (kernel_type != KERNEL_TYPE_OPENBSD)
return GRUB_ERR_NONE;
return grub_openbsd_find_ramdisk64 (elf->file, kern_start,
kern_chunk_src, &openbsd_ramdisk);
}
else
return grub_error (GRUB_ERR_BAD_OS, "invalid ELF");
@ -1306,6 +1319,8 @@ grub_bsd_load (int argc, char *argv[])
grub_loader_unset ();
grub_memset (&openbsd_ramdisk, 0, sizeof (openbsd_ramdisk));
if (argc == 0)
{
grub_error (GRUB_ERR_BAD_ARGUMENT, "no kernel specified");
@ -1874,11 +1889,55 @@ grub_cmd_freebsd_module_elf (grub_command_t cmd __attribute__ ((unused)),
return err;
}
static grub_err_t
grub_cmd_openbsd_ramdisk (grub_command_t cmd __attribute__ ((unused)),
int argc, char *args[])
{
grub_file_t file;
grub_size_t size;
if (argc != 1)
return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required");
if (kernel_type != KERNEL_TYPE_OPENBSD)
return grub_error (GRUB_ERR_BAD_OS, "no kOpenBSD loaded");
if (!openbsd_ramdisk.max_size)
return grub_error (GRUB_ERR_BAD_OS, "your kOpenBSD doesn't support ramdisk");
file = grub_gzfile_open (args[0], 1);
if (! file)
return grub_error (GRUB_ERR_FILE_NOT_FOUND,
"couldn't load ramdisk");
size = grub_file_size (file);
if (size > openbsd_ramdisk.max_size)
{
grub_file_close (file);
return grub_error (GRUB_ERR_BAD_OS, "your kOpenBSD supports ramdisk only"
" up to %u bytes, however you supplied a %u bytes one",
openbsd_ramdisk.max_size, size);
}
if (grub_file_read (file, openbsd_ramdisk.target, size)
!= (grub_ssize_t) (size))
{
grub_file_close (file);
grub_error_push ();
return grub_error (GRUB_ERR_BAD_OS, "couldn't read file %s", args[0]);
}
grub_memset (openbsd_ramdisk.target + size, 0,
openbsd_ramdisk.max_size - size);
*openbsd_ramdisk.size = ALIGN_UP (size, 512);
return GRUB_ERR_NONE;
}
static grub_extcmd_t cmd_freebsd, cmd_openbsd, cmd_netbsd;
static grub_command_t cmd_freebsd_loadenv, cmd_freebsd_module;
static grub_command_t cmd_netbsd_module, cmd_freebsd_module_elf;
static grub_command_t cmd_netbsd_module_elf;
static grub_command_t cmd_netbsd_module_elf, cmd_openbsd_ramdisk;
GRUB_MOD_INIT (bsd)
{
@ -1910,6 +1969,10 @@ GRUB_MOD_INIT (bsd)
grub_register_command ("kfreebsd_module_elf", grub_cmd_freebsd_module_elf,
0, N_("Load FreeBSD kernel module (ELF)."));
cmd_openbsd_ramdisk = grub_register_command ("kopenbsd_ramdisk",
grub_cmd_openbsd_ramdisk, 0,
"Load kOpenBSD ramdisk. ");
my_mod = mod;
}
@ -1924,6 +1987,7 @@ GRUB_MOD_FINI (bsd)
grub_unregister_command (cmd_netbsd_module);
grub_unregister_command (cmd_freebsd_module_elf);
grub_unregister_command (cmd_netbsd_module_elf);
grub_unregister_command (cmd_openbsd_ramdisk);
grub_bsd_unload ();
}

View file

@ -503,4 +503,118 @@ SUFFIX (grub_netbsd_load_elf_meta) (struct grub_relocator *relocator,
return GRUB_ERR_NONE;
}
grub_err_t
SUFFIX(grub_openbsd_find_ramdisk) (grub_file_t file,
grub_addr_t kern_start,
void *kern_chunk_src,
struct grub_openbsd_ramdisk_descriptor *desc)
{
unsigned symoff, stroff, symsize, strsize, symentsize;
{
grub_err_t err;
Elf_Ehdr e;
Elf_Shdr *s;
char *shdr;
err = read_headers (file, &e, &shdr);
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))
{
grub_free (shdr);
return GRUB_ERR_NONE;
}
symsize = s->sh_size;
symentsize = s->sh_entsize;
symoff = s->sh_offset;
s = (Elf_Shdr *) (shdr + e.e_shentsize * s->sh_link);
stroff = s->sh_offset;
strsize = s->sh_size;
grub_free (shdr);
}
{
Elf_Sym *syms, *sym, *imagesym = NULL, *sizesym = NULL;
unsigned i;
char *strs;
syms = grub_malloc (symsize);
if (!syms)
return grub_errno;
if (grub_file_seek (file, symoff) == (grub_off_t) -1)
{
grub_free (syms);
return grub_errno;
}
if (grub_file_read (file, syms, symsize) != (grub_ssize_t) symsize)
{
grub_free (syms);
if (! grub_errno)
return grub_error (GRUB_ERR_BAD_OS, "invalid ELF");
return grub_errno;
}
strs = grub_malloc (strsize);
if (!strs)
{
grub_free (syms);
return grub_errno;
}
if (grub_file_seek (file, stroff) == (grub_off_t) -1)
return grub_errno;
if (grub_file_read (file, strs, strsize) != (grub_ssize_t) strsize)
{
grub_free (syms);
grub_free (strs);
if (! grub_errno)
return grub_error (GRUB_ERR_BAD_OS, "invalid ELF");
return grub_errno;
}
for (i = 0, sym = syms; i < symsize / symentsize;
i++, sym = (Elf_Sym *) ((char *) sym + symentsize))
{
if (ELF_ST_TYPE (sym->st_info) != STT_OBJECT)
continue;
if (!sym->st_name)
continue;
if (grub_strcmp (strs + sym->st_name, "rd_root_image") == 0)
imagesym = sym;
if (grub_strcmp (strs + sym->st_name, "rd_root_size") == 0)
sizesym = sym;
if (imagesym && sizesym)
break;
}
if (!imagesym || !sizesym)
{
grub_free (syms);
grub_free (strs);
return GRUB_ERR_NONE;
}
if (sizeof (*desc->size) != sizesym->st_size)
{
grub_free (syms);
grub_free (strs);
return grub_error (GRUB_ERR_BAD_OS, "unexpected size of rd_root_size");
}
desc->max_size = imagesym->st_size;
desc->target = (imagesym->st_value & 0xFFFFFF) - kern_start
+ (grub_uint8_t *) kern_chunk_src;
desc->size = (grub_uint32_t *) ((sizesym->st_value & 0xFFFFFF) - kern_start
+ (grub_uint8_t *) kern_chunk_src);
grub_free (syms);
grub_free (strs);
return GRUB_ERR_NONE;
}
}

View file

@ -99,6 +99,22 @@ grub_err_t grub_freebsd_add_meta_module (char *filename, char *type,
int argc, char **argv,
grub_addr_t addr, grub_uint32_t size);
struct grub_openbsd_ramdisk_descriptor
{
grub_size_t max_size;
grub_uint8_t *target;
grub_uint32_t *size;
};
grub_err_t grub_openbsd_find_ramdisk32 (grub_file_t file,
grub_addr_t kern_start,
void *kern_chunk_src,
struct grub_openbsd_ramdisk_descriptor *desc);
grub_err_t grub_openbsd_find_ramdisk64 (grub_file_t file,
grub_addr_t kern_start,
void *kern_chunk_src,
struct grub_openbsd_ramdisk_descriptor *desc);
extern grub_uint8_t grub_bsd64_trampoline_start, grub_bsd64_trampoline_end;
extern grub_uint32_t grub_bsd64_trampoline_selfjump;
extern grub_uint32_t grub_bsd64_trampoline_gdt;