From ecde61b4909e2a4683bf17ee30232994df0b5712 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Thu, 26 Aug 2010 02:46:30 +0200 Subject: [PATCH] openbsd ramdisk support --- grub-core/loader/i386/bsd.c | 70 ++++++++++++++++++++- grub-core/loader/i386/bsdXX.c | 114 ++++++++++++++++++++++++++++++++++ include/grub/i386/bsd.h | 16 +++++ 3 files changed, 197 insertions(+), 3 deletions(-) diff --git a/grub-core/loader/i386/bsd.c b/grub-core/loader/i386/bsd.c index 6399cb1e3..770c6f278 100644 --- a/grub-core/loader/i386/bsd.c +++ b/grub-core/loader/i386/bsd.c @@ -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 (); } diff --git a/grub-core/loader/i386/bsdXX.c b/grub-core/loader/i386/bsdXX.c index f053e7e13..073f01da2 100644 --- a/grub-core/loader/i386/bsdXX.c +++ b/grub-core/loader/i386/bsdXX.c @@ -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; + } +} diff --git a/include/grub/i386/bsd.h b/include/grub/i386/bsd.h index a6abd7e90..53008cdaf 100644 --- a/include/grub/i386/bsd.h +++ b/include/grub/i386/bsd.h @@ -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;