]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
openbsd ramdisk support
authorVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Thu, 26 Aug 2010 00:46:30 +0000 (02:46 +0200)
committerVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Thu, 26 Aug 2010 00:46:30 +0000 (02:46 +0200)
grub-core/loader/i386/bsd.c
grub-core/loader/i386/bsdXX.c
include/grub/i386/bsd.h

index 6399cb1e39ae5a40f284f28d7add5e4bd97f8394..770c6f2785b97b7c86784fc9d8be6561bc404eac 100644 (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 ();
 }
index f053e7e138f44b4a947ae044865449999aa08f8a..073f01da2d746aad692247db7dabb9e458cc90a2 100644 (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;
+  }
+}
index a6abd7e90cfea5d6705ea33741f3ac20d3f2025a..53008cdaf14d33ab9eabfe4bb8340ee98ad6fdc5 100644 (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;