commit-grub
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[2352] 2009-06-21 Vladimir Serbinenko <address@hidden>


From: Vladimir Serbinenko
Subject: [2352] 2009-06-21 Vladimir Serbinenko <address@hidden>
Date: Sun, 21 Jun 2009 15:48:10 +0000

Revision: 2352
          http://svn.sv.gnu.org/viewvc/?view=rev&root=grub&revision=2352
Author:   phcoder
Date:     2009-06-21 15:48:10 +0000 (Sun, 21 Jun 2009)
Log Message:
-----------
2009-06-21  Vladimir Serbinenko  <address@hidden>

        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

Modified Paths:
--------------
    trunk/grub2/ChangeLog
    trunk/grub2/conf/i386-pc.rmk
    trunk/grub2/include/grub/elfload.h
    trunk/grub2/include/grub/i386/bsd.h
    trunk/grub2/include/grub/multiboot2.h
    trunk/grub2/kern/elf.c
    trunk/grub2/loader/i386/bsd.c
    trunk/grub2/loader/i386/pc/multiboot2.c
    trunk/grub2/loader/ieee1275/multiboot2.c
    trunk/grub2/loader/powerpc/ieee1275/linux.c
    trunk/grub2/loader/sparc64/ieee1275/linux.c

Added Paths:
-----------
    trunk/grub2/loader/i386/bsd32.c
    trunk/grub2/loader/i386/bsd64.c
    trunk/grub2/loader/i386/bsdXX.c

Modified: trunk/grub2/ChangeLog
===================================================================
--- trunk/grub2/ChangeLog       2009-06-21 11:21:59 UTC (rev 2351)
+++ trunk/grub2/ChangeLog       2009-06-21 15:48:10 UTC (rev 2352)
@@ -1,3 +1,37 @@
+2009-06-21  Vladimir Serbinenko  <address@hidden>
+
+       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  <address@hidden>
 
        * util/grub-mkconfig.in (GRUB_DISABLE_LINUX_RECOVERY): Export

Modified: trunk/grub2/conf/i386-pc.rmk
===================================================================
--- trunk/grub2/conf/i386-pc.rmk        2009-06-21 11:21:59 UTC (rev 2351)
+++ trunk/grub2/conf/i386-pc.rmk        2009-06-21 15:48:10 UTC (rev 2352)
@@ -329,7 +329,7 @@
 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)

Modified: trunk/grub2/include/grub/elfload.h
===================================================================
--- trunk/grub2/include/grub/elfload.h  2009-06-21 11:21:59 UTC (rev 2351)
+++ trunk/grub2/include/grub/elfload.h  2009-06-21 15:48:10 UTC (rev 2352)
@@ -37,9 +37,9 @@
 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);

Modified: trunk/grub2/include/grub/i386/bsd.h
===================================================================
--- trunk/grub2/include/grub/i386/bsd.h 2009-06-21 11:21:59 UTC (rev 2351)
+++ trunk/grub2/include/grub/i386/bsd.h 2009-06-21 15:48:10 UTC (rev 2352)
@@ -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,7 +230,22 @@
 
 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;
 extern grub_uint32_t grub_bsd64_trampoline_gdt;

Modified: trunk/grub2/include/grub/multiboot2.h
===================================================================
--- trunk/grub2/include/grub/multiboot2.h       2009-06-21 11:21:59 UTC (rev 
2351)
+++ trunk/grub2/include/grub/multiboot2.h       2009-06-21 15:48:10 UTC (rev 
2352)
@@ -45,10 +45,10 @@
 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);

Modified: trunk/grub2/kern/elf.c
===================================================================
--- trunk/grub2/kern/elf.c      2009-06-21 11:21:59 UTC (rev 2351)
+++ trunk/grub2/kern/elf.c      2009-06-21 15:48:10 UTC (rev 2352)
@@ -228,14 +228,15 @@
   {
     grub_elf32_load_hook_t load_hook = (grub_elf32_load_hook_t) hook;
     grub_addr_t load_addr;
+    int do_load = 1;
 
-    if (phdr->p_type != PT_LOAD)
-      return 0;
-
     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_hook_t load_hook = (grub_elf64_load_hook_t) hook;
     grub_addr_t load_addr;
+    int do_load = 1;
 
-    if (phdr->p_type != PT_LOAD)
-      return 0;
-
     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;
 

Modified: trunk/grub2/loader/i386/bsd.c
===================================================================
--- trunk/grub2/loader/i386/bsd.c       2009-06-21 11:21:59 UTC (rev 2351)
+++ trunk/grub2/loader/i386/bsd.c       2009-06-21 15:48:10 UTC (rev 2352)
@@ -116,7 +116,7 @@
     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 @@
   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 @@
        }
     }
 
-  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 @@
 }
 
 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 @@
 }
 
 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 @@
   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 @@
                         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,10 +1028,28 @@
     }
 
   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)
     grub_file_close (file);
@@ -1007,8 +1057,50 @@
   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 @@
   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_unregister_command (cmd_freebsd_loadenv);
   grub_unregister_command (cmd_freebsd_module);
+  grub_unregister_command (cmd_freebsd_module_elf);
 
   if (mod_buf)
     {

Added: trunk/grub2/loader/i386/bsd32.c
===================================================================
--- trunk/grub2/loader/i386/bsd32.c                             (rev 0)
+++ trunk/grub2/loader/i386/bsd32.c     2009-06-21 15:48:10 UTC (rev 2352)
@@ -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"

Added: trunk/grub2/loader/i386/bsd64.c
===================================================================
--- trunk/grub2/loader/i386/bsd64.c                             (rev 0)
+++ trunk/grub2/loader/i386/bsd64.c     2009-06-21 15:48:10 UTC (rev 2352)
@@ -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"

Added: trunk/grub2/loader/i386/bsdXX.c
===================================================================
--- trunk/grub2/loader/i386/bsdXX.c                             (rev 0)
+++ trunk/grub2/loader/i386/bsdXX.c     2009-06-21 15:48:10 UTC (rev 2352)
@@ -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;
+}

Modified: trunk/grub2/loader/i386/pc/multiboot2.c
===================================================================
--- trunk/grub2/loader/i386/pc/multiboot2.c     2009-06-21 11:21:59 UTC (rev 
2351)
+++ trunk/grub2/loader/i386/pc/multiboot2.c     2009-06-21 15:48:10 UTC (rev 
2352)
@@ -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_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",

Modified: trunk/grub2/loader/ieee1275/multiboot2.c
===================================================================
--- trunk/grub2/loader/ieee1275/multiboot2.c    2009-06-21 11:21:59 UTC (rev 
2351)
+++ trunk/grub2/loader/ieee1275/multiboot2.c    2009-06-21 15:48:10 UTC (rev 
2352)
@@ -36,10 +36,18 @@
 
 /* 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 @@
 
 /* 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",

Modified: trunk/grub2/loader/powerpc/ieee1275/linux.c
===================================================================
--- trunk/grub2/loader/powerpc/ieee1275/linux.c 2009-06-21 11:21:59 UTC (rev 
2351)
+++ trunk/grub2/loader/powerpc/ieee1275/linux.c 2009-06-21 15:48:10 UTC (rev 
2352)
@@ -132,8 +132,15 @@
 
   /* 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 @@
 
   /* 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;

Modified: trunk/grub2/loader/sparc64/ieee1275/linux.c
===================================================================
--- trunk/grub2/loader/sparc64/ieee1275/linux.c 2009-06-21 11:21:59 UTC (rev 
2351)
+++ trunk/grub2/loader/sparc64/ieee1275/linux.c 2009-06-21 15:48:10 UTC (rev 
2352)
@@ -272,8 +272,15 @@
 
   /* 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;





reply via email to

[Prev in Thread] Current Thread [Next in Thread]