]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
Allow compression algorithm specification
authorVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Tue, 21 Sep 2010 18:30:28 +0000 (20:30 +0200)
committerVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Tue, 21 Sep 2010 18:30:28 +0000 (20:30 +0200)
grub-core/Makefile.core.def
grub-core/boot/decompressor/minilib.c [moved from grub-core/boot/decompressor.c with 76% similarity]
grub-core/boot/decompressor/none.c [new file with mode: 0644]
grub-core/boot/decompressor/xz.c [new file with mode: 0644]
util/grub-mkimage.c

index 58fd7cf5d3a26ef3601af6c0267a0b70c8dba25c..48579896c6b12a8eb07be023daffafd995e055a8 100644 (file)
@@ -276,9 +276,10 @@ image = {
 };
 
 image = {
-  name = decompress;
+  name = xz_decompress;
   mips = boot/mips/startup_raw.S;
-  common = boot/decompressor.c;
+  common = boot/decompressor/minilib.c;
+  common = boot/decompressor/xz.c;
   common = lib/xzembed/xz_dec_bcj.c;
   common = lib/xzembed/xz_dec_lzma2.c;
   common = lib/xzembed/xz_dec_stream.c;
@@ -293,6 +294,19 @@ image = {
   enable = mips;
 };
 
+image = {
+  name = none_decompress;
+  mips = boot/mips/startup_raw.S;
+  common = boot/decompressor/none.c;
+
+  mips_cppflags = '-DGRUB_EMBED_DECOMPRESSOR=1 -DGRUB_MACHINE_LINK_ADDR=0x80200000';
+
+  objcopyflags = '-O binary';
+  ldflags = '-lgcc -static-libgcc -Wl,-Ttext,0x80100000';
+  cflags = '-static-libgcc';
+  enable = mips;
+};
+
 image = {
   name = fwstart;
   mips_yeeloong = boot/mips/yeeloong/fwstart.S;
similarity index 76%
rename from grub-core/boot/decompressor.c
rename to grub-core/boot/decompressor/minilib.c
index 604fc754c72a026eafa8d90ce84364ddac016b1e..d1f021933bdb399a95128cdb9b556675f52676bc 100644 (file)
@@ -20,9 +20,6 @@
 #include <grub/misc.h>
 #include <grub/decompressor.h>
 
-#include "xz.h"
-#include "xz_stream.h"
-
 void *
 memset (void *s, int c, grub_size_t len)
 {
@@ -100,39 +97,3 @@ find_scratch (void *src, void *dst, unsigned long srcsize,
     grub_decompressor_scratch = (char *) dst + dstsize;
   return;
 }
-
-void
-grub_decompress_core (void *src, void *dst, unsigned long srcsize,
-                     unsigned long dstsize)
-{
-  struct xz_dec *dec;
-  struct xz_buf buf;
-
-  find_scratch (src, dst, srcsize, dstsize);
-
-  dec = xz_dec_init (GRUB_DECOMPRESSOR_DICT_SIZE);
-
-  buf.in = src;
-  buf.in_pos = 0;
-  buf.in_size = srcsize;
-  buf.out = dst;
-  buf.out_pos = 0;
-  buf.out_size = dstsize;
-
-  while (buf.in_pos != buf.in_size)
-    {
-      enum xz_ret xzret;
-      xzret = xz_dec_run (dec, &buf);
-      switch (xzret)
-       {
-       case XZ_MEMLIMIT_ERROR:
-       case XZ_FORMAT_ERROR:
-       case XZ_OPTIONS_ERROR:
-       case XZ_DATA_ERROR:
-       case XZ_BUF_ERROR:
-         return;
-       default:
-         break;
-       }
-    }
-}
diff --git a/grub-core/boot/decompressor/none.c b/grub-core/boot/decompressor/none.c
new file mode 100644 (file)
index 0000000..44f56ce
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2010  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/decompressor.h>
+
+void
+grub_decompress_core (void *src, void *dest, unsigned long n,
+                     unsigned long dstsize __attribute__ ((unused)))
+{
+  char *d = (char *) dest;
+  const char *s = (const char *) src;
+
+  if (d < s)
+    while (n--)
+      *d++ = *s++;
+  else
+    {
+      d += n;
+      s += n;
+
+      while (n--)
+       *--d = *--s;
+    }
+}
diff --git a/grub-core/boot/decompressor/xz.c b/grub-core/boot/decompressor/xz.c
new file mode 100644 (file)
index 0000000..2279118
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2010  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/types.h>
+#include <grub/misc.h>
+#include <grub/decompressor.h>
+
+#include "xz.h"
+#include "xz_stream.h"
+
+void
+grub_decompress_core (void *src, void *dst, unsigned long srcsize,
+                     unsigned long dstsize)
+{
+  struct xz_dec *dec;
+  struct xz_buf buf;
+
+  find_scratch (src, dst, srcsize, dstsize);
+
+  dec = xz_dec_init (GRUB_DECOMPRESSOR_DICT_SIZE);
+
+  buf.in = src;
+  buf.in_pos = 0;
+  buf.in_size = srcsize;
+  buf.out = dst;
+  buf.out_pos = 0;
+  buf.out_size = dstsize;
+
+  while (buf.in_pos != buf.in_size)
+    {
+      enum xz_ret xzret;
+      xzret = xz_dec_run (dec, &buf);
+      switch (xzret)
+       {
+       case XZ_MEMLIMIT_ERROR:
+       case XZ_FORMAT_ERROR:
+       case XZ_OPTIONS_ERROR:
+       case XZ_DATA_ERROR:
+       case XZ_BUF_ERROR:
+         return;
+       default:
+         break;
+       }
+    }
+}
index ee007a54b2637f98876ec95a9f567227bfbf96ac..75343ac30b0d68148bfacb97b5f41b932390bd27 100644 (file)
 #define ALIGN_ADDR(x) (ALIGN_UP((x), image_target->voidp_sizeof))
 
 #define TARGET_NO_FIELD 0xffffffff
+
+typedef enum {
+  COMPRESSION_AUTO, COMPRESSION_NONE, COMPRESSION_XZ
+} grub_compression_t;
+
 struct image_target_desc
 {
   const char *name;
@@ -60,7 +65,8 @@ struct image_target_desc
   enum
     {
       PLATFORM_FLAGS_NONE = 0,
-      PLATFORM_FLAGS_LZMA = 1
+      PLATFORM_FLAGS_LZMA = 1,
+      PLATFORM_FLAGS_DECOMPRESSORS = 2
     } flags;
   unsigned prefix;
   unsigned prefix_end;
@@ -75,6 +81,7 @@ struct image_target_desc
   unsigned install_dos_part, install_bsd_part;
   grub_uint64_t link_addr;
   unsigned mod_gap, mod_align;
+  grub_compression_t default_compression;
 };
 
 struct image_target_desc image_targets[] =
@@ -248,7 +255,7 @@ struct image_target_desc image_targets[] =
       .voidp_sizeof = 4,
       .bigendian = 0,
       .id = IMAGE_YEELOONG_FLASH, 
-      .flags = PLATFORM_FLAGS_LZMA,
+      .flags = PLATFORM_FLAGS_DECOMPRESSORS,
       .prefix = GRUB_KERNEL_MIPS_YEELOONG_PREFIX,
       .prefix_end = GRUB_KERNEL_MIPS_YEELOONG_PREFIX_END,
       .raw_size = 0,
@@ -261,14 +268,15 @@ struct image_target_desc image_targets[] =
       .install_bsd_part = TARGET_NO_FIELD,
       .link_addr = GRUB_KERNEL_MIPS_YEELOONG_LINK_ADDR,
       .elf_target = EM_MIPS,
-      .link_align = GRUB_KERNEL_MIPS_YEELOONG_LINK_ALIGN
+      .link_align = GRUB_KERNEL_MIPS_YEELOONG_LINK_ALIGN,
+      .default_compression = COMPRESSION_XZ
     },
     {
       .name = "mipsel-yeeloong-elf",
       .voidp_sizeof = 4,
       .bigendian = 0,
       .id = IMAGE_YEELOONG_ELF, 
-      .flags = PLATFORM_FLAGS_LZMA,
+      .flags = PLATFORM_FLAGS_DECOMPRESSORS,
       .prefix = GRUB_KERNEL_MIPS_YEELOONG_PREFIX,
       .prefix_end = GRUB_KERNEL_MIPS_YEELOONG_PREFIX_END,
       .raw_size = 0,
@@ -281,7 +289,8 @@ struct image_target_desc image_targets[] =
       .install_bsd_part = TARGET_NO_FIELD,
       .link_addr = GRUB_KERNEL_MIPS_YEELOONG_LINK_ADDR,
       .elf_target = EM_MIPS,
-      .link_align = GRUB_KERNEL_MIPS_YEELOONG_LINK_ALIGN
+      .link_align = GRUB_KERNEL_MIPS_YEELOONG_LINK_ALIGN,
+      .default_compression = COMPRESSION_NONE
     },
     {
       .name = "powerpc-ieee1275",
@@ -483,7 +492,39 @@ compress_kernel_lzma (char *kernel_img, size_t kernel_size,
   memcpy (*core_img, kernel_img, raw_size);
 
   *core_size = kernel_size - raw_size;
-  if (LzmaEncode ((unsigned char *) *core_img + raw_size, core_size,
+  if (LzmaEncode ((unsigned char *) *core_img + raw_size, core_size - raw_size,
+                 (unsigned char *) kernel_img + raw_size,
+                 kernel_size - raw_size,
+                 &props, out_props, &out_props_size,
+                 0, NULL, &g_Alloc, &g_Alloc) != SZ_OK)
+    grub_util_error (_("cannot compress the kernel image"));
+
+  *core_size += raw_size;
+}
+
+static void
+compress_kernel_xz (char *kernel_img, size_t kernel_size,
+                   char **core_img, size_t *core_size, size_t raw_size)
+{
+  CLzmaEncProps props;
+  unsigned char out_props[5];
+  size_t out_props_size = 5;
+
+  LzmaEncProps_Init(&props);
+  props.dictSize = 1 << 16;
+  props.lc = 3;
+  props.lp = 0;
+  props.pb = 2;
+  props.numThreads = 1;
+
+  if (kernel_size < raw_size)
+    grub_util_error (_("the core image is too small"));
+
+  *core_img = xmalloc (kernel_size);
+  memcpy (*core_img, kernel_img, raw_size);
+
+  *core_size = kernel_size - raw_size;
+  if (LzmaEncode ((unsigned char *) *core_img + raw_size, core_size - raw_size,
                  (unsigned char *) kernel_img + raw_size,
                  kernel_size - raw_size,
                  &props, out_props, &out_props_size,
@@ -495,7 +536,8 @@ compress_kernel_lzma (char *kernel_img, size_t kernel_size,
 
 static void
 compress_kernel (struct image_target_desc *image_target, char *kernel_img,
-                size_t kernel_size, char **core_img, size_t *core_size)
+                size_t kernel_size, char **core_img, size_t *core_size,
+                grub_compression_t comp)
 {
  if (image_target->flags & PLATFORM_FLAGS_LZMA)
    {
@@ -504,6 +546,14 @@ compress_kernel (struct image_target_desc *image_target, char *kernel_img,
      return;
    }
 
+ if (image_target->flags & PLATFORM_FLAGS_DECOMPRESSORS
+     && (comp == COMPRESSION_XZ))
+   {
+     compress_kernel_xz (kernel_img, kernel_size, core_img,
+                        core_size, image_target->raw_size);
+     return;
+   }
+
   *core_img = xmalloc (kernel_size);
   memcpy (*core_img, kernel_img, kernel_size);
   *core_size = kernel_size;
@@ -527,7 +577,8 @@ struct fixup_block_list
 static void
 generate_image (const char *dir, char *prefix, FILE *out, char *mods[],
                char *memdisk_path, char *config_path,
-               struct image_target_desc *image_target, int note)
+               struct image_target_desc *image_target, int note,
+               grub_compression_t comp)
 {
   char *kernel_img, *core_img;
   size_t kernel_size, total_module_size, core_size, exec_size;
@@ -539,6 +590,10 @@ generate_image (const char *dir, char *prefix, FILE *out, char *mods[],
   grub_uint64_t start_address;
   void *rel_section;
   grub_size_t reloc_size, align;
+
+  if (comp == COMPRESSION_AUTO)
+    comp = image_target->default_compression;
+
   path_list = grub_util_resolve_dependencies (dir, "moddep.lst", mods);
 
   kernel_path = grub_util_get_path (dir, "kernel.img");
@@ -655,7 +710,7 @@ generate_image (const char *dir, char *prefix, FILE *out, char *mods[],
 
   grub_util_info ("kernel_img=%p, kernel_size=0x%x", kernel_img, kernel_size);
   compress_kernel (image_target, kernel_img, kernel_size + total_module_size,
-                  &core_img, &core_size);
+                  &core_img, &core_size, comp);
 
   grub_util_info ("the core size is 0x%x", core_size);
 
@@ -680,15 +735,27 @@ generate_image (const char *dir, char *prefix, FILE *out, char *mods[],
        = grub_host_to_target32 (-2);
     }
 
-  if (image_target->id == IMAGE_YEELOONG_FLASH
-      || image_target->id == IMAGE_YEELOONG_ELF)
+  if (image_target->flags & PLATFORM_FLAGS_DECOMPRESSORS)
     {
       char *full_img;
       size_t full_size;
       char *decompress_path, *decompress_img;
       size_t decompress_size;
+      const char *name;
+
+      switch (comp)
+       {
+       case COMPRESSION_XZ:
+         name = "xz_decompress.img";
+         break;
+       case COMPRESSION_NONE:
+         name = "none_decompress.img";
+         break;
+       default:
+         grub_util_error ("unknown compression %d\n", comp);
+       }
       
-      decompress_path = grub_util_get_path (dir, "decompress.img");
+      decompress_path = grub_util_get_path (dir, name);
       decompress_size = grub_util_get_image_size (decompress_path);
       decompress_img = grub_util_read_image (decompress_path);
 
@@ -1253,6 +1320,7 @@ static struct option options[] =
     {"output", required_argument, 0, 'o'},
     {"note", no_argument, 0, 'n'},
     {"format", required_argument, 0, 'O'},
+    {"compression", required_argument, 0, 'C'},
     {"help", no_argument, 0, 'h'},
     {"version", no_argument, 0, 'V'},
     {"verbose", no_argument, 0, 'v'},
@@ -1295,6 +1363,7 @@ Make a bootable image of GRUB.\n\
   -o, --output=FILE       output a generated image to FILE [default=stdout]\n\
   -O, --format=FORMAT     generate an image in format\n\
                           available formats: %s\n\
+  -C, --compression=(xz|none|auto)  choose the compression to use\n\
   -h, --help              display this message and exit\n\
   -V, --version           print version information and exit\n\
   -v, --verbose           print verbose messages\n\
@@ -1321,6 +1390,7 @@ main (int argc, char *argv[])
   FILE *fp = stdout;
   int note = 0;
   struct image_target_desc *image_target = NULL;
+  grub_compression_t comp = COMPRESSION_AUTO;
 
   set_program_name (argv[0]);
 
@@ -1328,7 +1398,7 @@ main (int argc, char *argv[])
 
   while (1)
     {
-      int c = getopt_long (argc, argv, "d:p:m:c:o:O:f:hVvn", options, 0);
+      int c = getopt_long (argc, argv, "d:p:m:c:o:O:f:C:hVvn", options, 0);
 
       if (c == -1)
        break;
@@ -1385,6 +1455,15 @@ main (int argc, char *argv[])
            config = xstrdup (optarg);
            break;
 
+         case 'C':
+           if (grub_strcmp (optarg, "xz") == 0)
+             comp = COMPRESSION_XZ;
+           else if (grub_strcmp (optarg, "none") == 0)
+             comp = COMPRESSION_NONE;
+           else
+             grub_util_error ("Unknown compression format %s", optarg);
+           break;
+
          case 'h':
            usage (0);
            break;
@@ -1443,7 +1522,7 @@ main (int argc, char *argv[])
 
   generate_image (dir, prefix ? : DEFAULT_DIRECTORY, fp,
                  argv + optind, memdisk, config,
-                 image_target, note);
+                 image_target, note, comp);
 
   fclose (fp);