Imported Upstream version 3.6 upstream/3.6
authorBdale Garbee <bdale@gag.com>
Tue, 20 May 2008 05:09:33 +0000 (23:09 -0600)
committerBdale Garbee <bdale@gag.com>
Tue, 20 May 2008 05:09:33 +0000 (23:09 -0600)
39 files changed:
ChangeLog
Make.defaults
Makefile
TODO
alloc.c
bootparams.c
choosers/simple.c
choosers/textmenu.c
config.c
docs/netbooting.txt
elilo-ia32.efi [deleted file]
elilo-ia64.efi [deleted file]
elilo.c
elilo.h
fileops.c
fileops.h
glue_localfs.c
glue_netfs.c
gnu-efi-3.0a-ia32.patch [deleted file]
gunzip.c [new file with mode: 0644]
gzip.h [new file with mode: 0644]
ia32/Makefile
ia32/bzimage.c [new file with mode: 0644]
ia32/gzip.c [new file with mode: 0644]
ia32/gzip_loader.c [new file with mode: 0644]
ia32/plain_loader.c [new file with mode: 0644]
ia32/sysdeps.h
ia32/system.c
ia64/gzip.c
ia64/gzip.h [deleted file]
ia64/gzip_loader.c
ia64/inflate.c [deleted file]
ia64/plain_loader.c
ia64/private.h
ia64/setjmp.S
ia64/sysdeps.h
ia64/system.c
inflate.c [new file with mode: 0644]
initrd.c

index 07aba8ed71973e9f0ce80d3bc25889df10c9610a..d2cbe27a8012fc359b483683292aa0b7178fcf0d 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,38 @@
+2006-01-09 Brett Johnson <brett@hp.com>
+       * Released 3.6
+2005-12-22 Alex Williamson <alex.williamson@hp.com>
+       * Fixed vmcode_name initialization in textmenu chooser
+2005-12-01 Alex Williamson <alex.williamson@hp.com>
+       * Applied patch from Fred Yang <fred.yang@intel.com> to support the
+         vmm= boot option.  This option specifies the kernel image for a
+         virtual machine monitor (aka hypervisor).  The vmm= and image=
+         options are used together to load both the hypervisor kernel and
+         the guest domain kernel into memory.  If a vmm= option is not
+         specified, elilo defaults to the old behavior of loading and booting
+         to the image= kernel.
+       * Added support for compressed image= files when used with the vmm=
+         option.  If the image= file is detected to be gzip compressed, the
+         image will be uncompressed into memory before it is provided to the
+         hypervisor.  Any combination of compressed and uncompressed images
+         can be used for the image and vmm options.
+2005-09-15 Brett Johnson <brett@hp.com>
+       * Applied patch from Tristan Gingold to add dcache flush and sync with
+         icache to gzip and plain loaders.  This ommision was just noticed now
+         due to the much larger caches in Montecito, and the smaller size of
+         Xen (as compared to the linux kernel).
+2004-09-27 Brett Johnson <brett@hp.com>
+       * Increase the hardcoded size of the texmenu chooser menu from 16 to 64
+2004-09-23 Brett Johnson <brett@hp.com>
+       * Fix for 924147.  Thanks to Stephanie Schaaf <sas@sgi.com> for a patch
+         that the fix is based on.
+2004-02-19 Brett Johnson <brett@hp.com>
+       * Fixed bug where default image initrd would carry over to another
+         image that was selected interactively (iff the newly selected image
+         did not have an initrd).
+       * Added support for subnet-specific config files in netfs.
+2004-02-17 Brett Johnson <brett@hp.com>
+       * integrated ia32 compressed kernel support from Matt Tolentino
+         <matthew.e.tolentino@intel.com>
 2003-08-20 Stephane Eranian <eranian@hpl.hp.com>
        * released 3.4
 2003-08-19 Stephane Eranian <eranian@hpl.hp.com>
        * released version 3.2
        * cleanup some GNU extension in fs/ext2fs.c (variable size array)
        * updated all documentation. Added netbooting.txt, simple_chooser.txt,
-          eliloalt.txt, elilovar.txt
+         eliloalt.txt, elilovar.txt
 2002-02-21 Stephane Eranian <eranian@hpl.hp.com>
        * added a Linux utility program (elilovar in tools) to set/read/delete 
          the EliloAlt EFI variable used to specify an alternate kernel to boot.
index 523f0fc70f420be172391fadbb508eb1c8a84efc..0a90776e0e2783c2fd7a3291460594addc86169f 100644 (file)
@@ -68,7 +68,7 @@ CPPFLAGS   = -DCONFIG_$(ARCH)
 OPTIMFLAGS = -O2 
 DEBUGFLAGS = -Wall
 CFLAGS    = $(OPTIMFLAGS) -fpic -fshort-wchar $(DEBUGFLAGS)
-LDFLAGS           = -nostdlib
+LDFLAGS           = -nostdlib -znocombreloc
 INSTALL           = install
 
 ifeq ($(CONFIG_machspec_netconfig),y)
@@ -95,37 +95,23 @@ ifeq ($(CONFIG_chooser_textmenu),y)
 CFLAGS += -DCONFIG_CHOOSER_TEXTMENU
 endif
 
+prefix         = /usr/bin/
+  # Redhat 8.0 ia32 gcc-3.x version is reported to produce working EFI binaries.
+  # Redhat 9.0 ia32 gcc-3.x version is reported to produce BAD binaries.
+CC             = $(prefix)gcc
+AS             = $(prefix)as
+LD             = $(prefix)ld
+AR             = $(prefix)ar
+RANLIB         = $(prefix)ranlib
+OBJCOPY                = $(prefix)objcopy
+
 ifeq ($(ARCH),ia64)
-  prefix       = 
-  prefix       = /opt/gcc3.1/bin/
-  CC           = $(prefix)gcc
-  AS           = $(prefix)as
-  LD           = $(prefix)ld
-  LD           = ld
-  AR           = $(prefix)ar
-  RANLIB       = $(prefix)ranlib
-  OBJCOPY      = $(prefix)objcopy
-
-GCC_VERSION=$(shell $(CROSS_COMPILE)$(CC) -v 2>&1 | fgrep 'gcc version' | cut -f3 -d' ' | cut -f1 -d'.')
-
-ifneq ($(GCC_VERSION),2)
+ GCC_VERSION=$(shell $(CROSS_COMPILE)$(CC) -v 2>&1 | fgrep 'gcc version' | cut -f3 -d' ' | cut -f1 -d'.')
+
+ ifneq ($(GCC_VERSION),2)
         CFLAGS += -frename-registers
-endif
-#
-# EFI specs allows only lower floating point partition to be used
-# 
-# Redhat 8.0 gcc-3.x version is reported to produce working EFI binaries.
-# Redhat 9.0 gcc-3.x version is reported to produce BAD binaries.
-#
-CFLAGS += -mfixed-range=f32-f127
-else
- ifeq ($(ARCH),ia32)
-  prefix       = 
-  CC           = $(prefix)gcc3
-  AS           = $(prefix)as
-  LD           = $(prefix)ld
-  AR           = $(prefix)ar
-  RANLIB       = $(prefix)ranlib
-  OBJCOPY      = $(prefix)objcopy
  endif
+
+ # EFI specs allows only lower floating point partition to be used
+ CFLAGS += -mfixed-range=f32-f127
 endif
index d8ec67d487a8a653f6ff1e1cd1b17074899c9519..5015faf441589b6b789eca2d98903b93e90f0ec4 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -61,7 +61,7 @@ endif
 FILES = elilo.o getopt.o strops.o loader.o \
         fileops.o util.o vars.o alloc.o chooser.o  \
        config.o initrd.o alternate.o bootparams.o \
-       fs/fs.o \
+       gunzip.o fs/fs.o \
        choosers/choosers.o \
        devschemes/devschemes.o \
        $(ARCH)/sysdeps.o \
diff --git a/TODO b/TODO
index d996a16a9a4a691515ba3ef83dc9007ecde37568..fb2696a27eacfb30cc2737105336ccf93eecd0b9 100644 (file)
--- a/TODO
+++ b/TODO
@@ -14,5 +14,3 @@ Some of the things TO DO:
        - Convert all filesystems (ext2fs, netfs) to use the FilesystemProtocol interface instead
 
        - cleanup x86 loader: use the same structure as IA-64
-
-       - support for subnetting in the config file when netbooting
diff --git a/alloc.c b/alloc.c
index 373fbdcc4176543087f50c1336cf30ee380ea543..349da9f24e6dbc85101f99fcc3645ff8077f1c51 100644 (file)
--- a/alloc.c
+++ b/alloc.c
@@ -129,7 +129,7 @@ alloc_pages(UINTN pgcnt, EFI_MEMORY_TYPE type, EFI_ALLOCATE_TYPE where, VOID *ad
 
        status = BS->AllocatePages(where, type , pgcnt, &tmp);
        if (EFI_ERROR(status)) {
-               ERR_PRT((L"allocator: AllocatePages(%d, %d, %d, 0x%lx) failed (%r)\n", where, type, pgcnt, tmp, status));
+               VERB_PRT(1, (L"allocator: AllocatePages(%d, %d, %d, 0x%lx) failed (%r)\n", where, type, pgcnt, tmp, status));
                return NULL;
        }
        /* XXX: will cause warning on IA-32 */
@@ -155,7 +155,7 @@ free(VOID *addr)
                if (p->addr == addr) goto found;
        }
        /* not found */
-        ERR_PRT((L"allocator: invalid free @ 0x%lx\n", addr));
+        VERB_PRT(1, (L"allocator: invalid free @ 0x%lx\n", addr));
        return; 
 found:
         DBG_PRT((L"free: %s @0x%lx size=%ld\n", 
index a6c9d7c47f7befac6fc1a70b08180139ccd976df..8859fcc48c1a0864e3ee25210629c56bf3929598 100644 (file)
@@ -38,7 +38,7 @@
  *     bp  : the address of the bootparams otherwise (opaque type)
  */
 VOID *
-create_boot_params(CHAR16 *args, memdesc_t *initrd, UINTN *cookie)
+create_boot_params(CHAR16 *args, memdesc_t *initrd, memdesc_t *vmcode, UINTN *cookie)
 {
 /* 
  * XXX: need cleanup
@@ -69,6 +69,7 @@ create_boot_params(CHAR16 *args, memdesc_t *initrd, UINTN *cookie)
         * Allocate memory for boot parameters.
         * This CANNOT be EfiLoaderData or EfiLoaderCode as the kernel
         * frees this region when initializing.
+        * FIXME:  Is this a bug?  (since the memory type *is* EfiLoaderData)
         */
 
        bp = (boot_params_t *)alloc(BOOT_PARAM_MEMSIZE, EfiLoaderData);
@@ -95,7 +96,7 @@ create_boot_params(CHAR16 *args, memdesc_t *initrd, UINTN *cookie)
         */
        Memset(bp, 0, BOOT_PARAM_MEMSIZE);
 
-       if (sysdeps_create_boot_params(bp, cp, initrd, cookie) == -1) return 0;
+       if (sysdeps_create_boot_params(bp, cp, initrd, vmcode, cookie) == -1) return 0;
 
        /*
         * Convert kernel command line args from UNICODE to ASCII and put them where
index 9b0725e4b8264712d56e8f329b0fcf836696707c..b246a910fad125e5dd59a9edab40edd9495fb931 100644 (file)
@@ -37,6 +37,7 @@ display_label_info(CHAR16 *name)
 {
        CHAR16 *desc;
        CHAR16 initrd_name[CMDLINE_MAXLEN];
+       CHAR16 vmcode_name[CMDLINE_MAXLEN];
        CHAR16 options_tmp[CMDLINE_MAXLEN];
        CHAR16 options[CMDLINE_MAXLEN];
        CHAR16 kname[FILENAME_MAXLEN];
@@ -46,9 +47,9 @@ display_label_info(CHAR16 *name)
                Print(L"desc   : %s\n", desc);
        }
 
-       initrd_name[0] = options_tmp[0] = kname[0] = CHAR_NULL;
+       initrd_name[0] = vmcode_name[0] = options_tmp[0] = kname[0] = CHAR_NULL;
 
-       if (find_label(name, kname, options_tmp, initrd_name) == -1) {
+       if (find_label(name, kname, options_tmp, initrd_name, vmcode_name) == -1) {
                StrCpy(kname, name);
                Print(L"\n");
        }
@@ -56,6 +57,7 @@ display_label_info(CHAR16 *name)
 
        Print(L"cmdline: %s %s\n", kname, options);
        if (initrd_name[0]) Print(L"initrd : %s\n", initrd_name);
+       if (vmcode_name[0]) Print(L"vmcode : %s\n", vmcode_name);
 }
 
 static VOID
@@ -247,6 +249,7 @@ simple_choose(CHAR16 **argv, INTN argc, INTN index, CHAR16 *kname, CHAR16 *cmdli
        CHAR16 buffer[CMDLINE_MAXLEN];
        CHAR16 alt_buffer[CMDLINE_MAXLEN];
        CHAR16 initrd_name[CMDLINE_MAXLEN];
+       CHAR16 vmcode_name[CMDLINE_MAXLEN];
        CHAR16 args[CMDLINE_MAXLEN];
        CHAR16 devname[CMDLINE_MAXLEN];
        CHAR16 dpath[FILENAME_MAXLEN];
@@ -259,7 +262,7 @@ simple_choose(CHAR16 **argv, INTN argc, INTN index, CHAR16 *kname, CHAR16 *cmdli
        display_message();
 
 restart:
-       initrd_name[0] = kname[0] = cmdline[0] = args[0] = CHAR_NULL;
+       initrd_name[0] = vmcode_name[0] = kname[0] = cmdline[0] = args[0] = CHAR_NULL;
 
        /* reset per image loader options */
        Memset(&elilo_opt.img_opt, 0, sizeof(elilo_opt.img_opt));
@@ -303,14 +306,14 @@ restart:
         * if no match is found, the args and initrd arguments may
         * still be modified by global options in the config file.
         */
-       ret = find_label(argv[index], kname, args, initrd_name);
+       ret = find_label((index < argc) ? argv[index] : NULL, kname, args, initrd_name, vmcode_name);
 
        /*
         * not found, so assume first argument is kernel name and
         * not label name 
         */
        if (ret == -1) {
-               if (argv[index]) 
+               if ((index < argc) && argv[index]) 
                        StrCpy(kname, argv[index]);
                else
                        StrCpy(kname, elilo_opt.default_kernel);
@@ -335,9 +338,14 @@ restart:
                StrCpy(elilo_opt.initrd, initrd_name);
        }
 
+       if (elilo_opt.vmcode[0] == CHAR_NULL && vmcode_name[0] != CHAR_NULL) {
+               StrCpy(elilo_opt.vmcode, vmcode_name);
+       }
+
        VERB_PRT(1,  { Print(L"kernel     is  '%s'\n", kname);
                       Print(L"arguments  are '%s'\n", args);
                        if (elilo_opt.initrd[0]) Print(L"initrd      is '%s'\n", elilo_opt.initrd);
+                       if (elilo_opt.vmcode[0]) Print(L"vmm         is '%s'\n", elilo_opt.vmcode);
                      });
 
        if (elilo_opt.prompt == 0) {
@@ -346,6 +354,7 @@ restart:
                ret = wait_timeout(elilo_opt.delay);
                if (ret != 0) {
                        elilo_opt.prompt = 1;
+                       elilo_opt.initrd[0] = CHAR_NULL;
                        elilo_opt.timeout =  ELILO_TIMEOUT_INFINITY;
                        goto restart;
                }
@@ -378,7 +387,8 @@ restart:
         */
        len = StrLen(BOOT_IMG_STR)      /* BOOT_IMAGE= */
             +StrLen(devname)           /* device name */
-            +StrLen(kname)             /* kernel name */
+                                       /* kernel name */
+            +elilo_opt.vmcode[0] ? StrLen(elilo_opt.vmcode) : StrLen(kname)
             +1                         /* space */
             +StrLen(args);             /* args length */
 
@@ -388,7 +398,10 @@ restart:
        }
        StrCpy(cmdline, L"BOOT_IMAGE=");
        StrCat(cmdline, devname);
-       StrCat(cmdline, kname);
+       if (elilo_opt.vmcode[0])
+               StrCat(cmdline, elilo_opt.vmcode);
+       else
+               StrCat(cmdline, kname);
        StrCat(cmdline, L" ");
        StrCat(cmdline, args);
 
index 9379b0e2034e7691709a609b8dde2635c08a1359..3210dda1b91e8344d2af5569e382d89440baceea 100644 (file)
@@ -28,7 +28,7 @@
 
 #include "elilo.h"
 
-#define MAX_LABELS     16
+#define MAX_LABELS     64
 #define MSGBUFLEN      4096
 
 static UINT8 msgbuf[MSGBUFLEN];
@@ -358,6 +358,7 @@ textmenu_choose(CHAR16 **argv, INTN argc, INTN index, CHAR16 *kname, CHAR16 *cmd
 #      define BOOT_IMG_STR     L"BOOT_IMAGE="
        CHAR16 label[CMDLINE_MAXLEN];
        CHAR16 initrd_name[CMDLINE_MAXLEN];
+       CHAR16 vmcode_name[CMDLINE_MAXLEN];
        CHAR16 args[CMDLINE_MAXLEN];
        CHAR16 devname[CMDLINE_MAXLEN];
        CHAR16 dpath[FILENAME_MAXLEN];
@@ -382,7 +383,7 @@ textmenu_choose(CHAR16 **argv, INTN argc, INTN index, CHAR16 *kname, CHAR16 *cmd
                nlabels++;
        }
 restart:
-       initrd_name[0] = kname[0] = cmdline[0] = args[0] = CHAR_NULL;
+       vmcode_name[0] = initrd_name[0] = kname[0] = cmdline[0] = args[0] = CHAR_NULL;
 
        /* reset per image loader options */
        Memset(&elilo_opt.img_opt, 0, sizeof(elilo_opt.img_opt));
@@ -400,7 +401,7 @@ restart:
        if (elilo_opt.alt_check && alternate_kernel(PromptBuf, sizeof(PromptBuf)) == 0) {
                argc    = argify(PromptBuf,sizeof(PromptBuf), argv); 
                index   = 0;
-               label[0] = args[0] = initrd_name[0] = 0;
+               label[0] = args[0] = initrd_name[0] = vmcode_name[0] = 0;
        }
 
        /*
@@ -412,16 +413,16 @@ restart:
         * still be modified by global options in the config file.
         */
        if (label[0])
-               ret = find_label(label, kname, args, initrd_name);
+               ret = find_label(label, kname, args, initrd_name, vmcode_name);
        else
-               ret = find_label(argv[index], kname, args, initrd_name);
+               ret = find_label((index < argc) ? argv[index] : NULL, kname, args, initrd_name, vmcode_name);
 
        /*
         * not found, so assume first argument is kernel name and
         * not label name 
         */
        if (ret == -1) {
-               if (argv[index]) 
+               if ((index < argc) && argv[index]) 
                        StrCpy(kname, argv[index]);
                else
                        StrCpy(kname, elilo_opt.default_kernel);
@@ -448,9 +449,14 @@ restart:
                StrCpy(elilo_opt.initrd, initrd_name);
        }
 
+       if (elilo_opt.vmcode[0] == CHAR_NULL && vmcode_name[0] != CHAR_NULL) {
+               StrCpy(elilo_opt.vmcode, vmcode_name);
+       }
+
        VERB_PRT(1,  { Print(L"kernel     is  '%s'\n", kname);
                       Print(L"arguments  are '%s'\n", args);
                        if (elilo_opt.initrd[0]) Print(L"initrd      is '%s'\n", elilo_opt.initrd);
+                       if (elilo_opt.vmcode[0]) Print(L"vmm         is '%s'\n", elilo_opt.vmcode);
                      });
 
        if (elilo_opt.prompt == 0) {
@@ -459,6 +465,7 @@ restart:
                ret = wait_timeout(elilo_opt.delay);
                if (ret != 0) {
                        elilo_opt.prompt = 1;
+                       elilo_opt.initrd[0] = CHAR_NULL;
                        elilo_opt.timeout =  ELILO_TIMEOUT_INFINITY;
                        goto restart;
                }
@@ -493,6 +500,7 @@ restart:
        len = StrLen(BOOT_IMG_STR)      /* BOOT_IMAGE= */
             +StrLen(devname)           /* device name */
             +StrLen(kname)             /* kernel name */
+            +elilo_opt.vmcode[0] ? StrLen(elilo_opt.vmcode) : StrLen(kname)
             +1                         /* space */
             +StrLen(args);             /* args length */
 
@@ -504,7 +512,10 @@ restart:
        }
        StrCpy(cmdline, L"BOOT_IMAGE=");
        StrCat(cmdline, devname);
-       StrCat(cmdline, kname);
+       if (elilo_opt.vmcode[0])
+               StrCat(cmdline, elilo_opt.vmcode);
+       else
+               StrCat(cmdline, kname);
        StrCat(cmdline, L" ");
        StrCat(cmdline, args);
 
index ac789b9bc61a35d6b0cc470ea70338a5157d244d..e24c0c0198613c2338215e4302ed12428e7c4295 100644 (file)
--- a/config.c
+++ b/config.c
@@ -68,6 +68,7 @@ typedef struct boot_image {
        CHAR16  kname[FILENAME_MAXLEN];
        CHAR16  options[MAX_STRING];
        CHAR16  initrd[FILENAME_MAXLEN];
+       CHAR16  vmcode[FILENAME_MAXLEN];
        CHAR16  root[FILENAME_MAXLEN];
        CHAR16  fallback[MAX_STRING];
        CHAR16  description[MAX_STRING];
@@ -93,6 +94,7 @@ typedef enum {
 typedef struct {
        CHAR16          root[FILENAME_MAXLEN];  /* globally defined root fs */
        CHAR16          initrd[FILENAME_MAXLEN];/* globally defined initrd  */
+       CHAR16          vmcode[FILENAME_MAXLEN];/* globally defined boot-time module  */
        CHAR16          options[MAX_STRING];
        CHAR16          default_image_name[MAX_STRING];
        CHAR16          message_file[MAX_MESSAGES][FILENAME_MAXLEN]; 
@@ -144,6 +146,7 @@ static config_option_t global_common_options[]={
 {OPT_BOOL,     OPT_GLOBAL,     L"noedd30",     NULL,           NULL,                   &global_config.edd30_no_force},
 {OPT_CMD,      OPT_GLOBAL,     L"append",      NULL,           NULL,                   global_config.options},
 {OPT_FILE,     OPT_GLOBAL,     L"initrd",      NULL,           NULL,                   global_config.initrd},
+{OPT_FILE,     OPT_GLOBAL,     L"vmm",         NULL,           NULL,                   global_config.vmcode},
 {OPT_FILE,     OPT_GLOBAL,     L"image",       do_image,       NULL,                   opt_offsetof(kname)},
 {OPT_BOOL,     OPT_GLOBAL,     L"checkalt",    NULL,           NULL,                   &global_config.alt_check},
 {OPT_STR,      OPT_GLOBAL,     L"chooser",     NULL,           check_chooser,          global_config.chooser},
@@ -168,6 +171,7 @@ static config_option_t image_common_options[]={
     {OPT_CMD,  OPT_IMAGE,      L"append",      do_options,     NULL,   opt_offsetof(options)},
     {OPT_CMD,  OPT_IMAGE,      L"literal",     do_literal,     NULL,   NULL},
     {OPT_FILE, OPT_IMAGE,      L"initrd",      NULL,           NULL,   opt_offsetof(initrd)},
+    {OPT_FILE, OPT_IMAGE,      L"vmm",         NULL,           NULL,   opt_offsetof(vmcode)},
     {OPT_STR,  OPT_IMAGE,      L"label",       NULL,           NULL,   opt_offsetof(label)},
     {OPT_FILE, OPT_IMAGE,      L"image",       do_image,       NULL,   opt_offsetof(kname)},
     {OPT_STR,  OPT_IMAGE,      L"description", NULL,           NULL,   opt_offsetof(description)},
@@ -843,7 +847,7 @@ get_config_file(VOID)
 }
 
 EFI_STATUS
-read_config(CHAR16 *filename, INTN retry)
+read_config(CHAR16 *filename)
 {
        EFI_STATUS status;
        INTN ret;
@@ -856,49 +860,8 @@ read_config(CHAR16 *filename, INTN retry)
 
        status = fops_open(filename, &config_fd);
        if (EFI_ERROR(status)) {
-               /* 
-                * if the user explicitely specified a filename and we can't
-                * find it, then we must fail.
-                */
-               if (elilo_opt.parse_only || retry == 0) {
-                       VERB_PRT(3, Print(L"cannot open config file %s\n", filename));
-                       return status;
-               }
-               /*
-                * if not already submitted filename,
-                */
-               if (StrCmp(filename, ELILO_ARCH_DEFAULT_CONFIG)) {
-                       /*
-                        * try the arch default file, now
-                        */
-                       VERB_PRT(3,Print(L"config file %s not found, trying %s\n", 
-                                  filename, ELILO_ARCH_DEFAULT_CONFIG));
-
-                       StrCpy(global_config.config_file,ELILO_ARCH_DEFAULT_CONFIG);
-
-                       status = fops_open(ELILO_ARCH_DEFAULT_CONFIG, &config_fd);
-               } 
-               /*
-                * if arch specific did not work, try generic
-                */
-               if (EFI_ERROR(status) && StrCmp(filename, ELILO_DEFAULT_CONFIG)) {
-                       /*
-                        * try the default file as a last resort
-                        */
-                       VERB_PRT(3,Print(L"config file %s not found, trying %s\n", 
-                                  ELILO_ARCH_DEFAULT_CONFIG, ELILO_DEFAULT_CONFIG));
-
-                       StrCpy(global_config.config_file, ELILO_DEFAULT_CONFIG);
-                       status = fops_open(ELILO_DEFAULT_CONFIG, &config_fd);
-               }
-               /*
-                * if nothing worked, then bail out
-                */
-               if (EFI_ERROR(status)) {
-                       VERB_PRT(3, Print(L"no valid config file found\n"));
-                       global_config.config_file[0] = CHAR_NULL;
-                       return status;
-               }
+                VERB_PRT(3, Print(L"cannot open config file %s\n", filename));
+                return status;
        }
        /*
         * start numbering at line 1
@@ -923,10 +886,10 @@ print_label_list(VOID)
 {
        boot_image_t *img, *dfl = global_config.default_image;
 
-       if (dfl) Print(L"%s ", dfl->label);
+       if (dfl) Print(L"\t%s\n", dfl->label);
 
        for (img = image_list; img; img = img->next) {
-               if (img != dfl) Print(L"%s   ", img->label);
+               if (img != dfl) Print(L"\t%s\n", img->label);
        }
 }
 
@@ -974,7 +937,7 @@ find_description(CHAR16 *label)
 }
 
 INTN
-find_label(CHAR16 *label, CHAR16 *kname, CHAR16 *options, CHAR16 *initrd)
+find_label(CHAR16 *label, CHAR16 *kname, CHAR16 *options, CHAR16 *initrd, CHAR16 *vmcode)
 {
        boot_image_t *img;
 
@@ -1007,6 +970,7 @@ find_label(CHAR16 *label, CHAR16 *kname, CHAR16 *options, CHAR16 *initrd)
        if (global_config.readonly) StrCat(options, L" ro");
 
        if (global_config.initrd[0]) StrCpy(initrd, global_config.initrd);
+       if (global_config.vmcode[0]) StrCpy(vmcode, global_config.vmcode);
 
        /* make sure we don't get garbage here */
        elilo_opt.sys_img_opts = NULL;
@@ -1044,12 +1008,17 @@ found:
        else if (global_config.initrd[0])
                StrCpy(initrd, global_config.initrd);
 
+       if (img->vmcode[0]) 
+               StrCpy(vmcode, img->vmcode);
+       else if (global_config.vmcode[0])
+               StrCpy(vmcode, global_config.vmcode);
+
        /*
         * point to architecture dependent options for this image
         */
        elilo_opt.sys_img_opts = &img->sys_img_opts;
 
-       DBG_PRT((L"label %s: kname=%s options=%s initrd=%s", img->label, kname, options, initrd));
+       DBG_PRT((L"label %s: kname=%s options=%s initrd=%s vmcode=%s", img->label, kname, options, initrd, vmcode));
 
        return 0;
 }
index 2f517403d8cec548dd23fb7c3b9ead95a6610b63..130cc11691ba665f1110292338fba6e8f71a409e 100644 (file)
@@ -126,7 +126,21 @@ only on two very common cases:
 
           This filename is an opportunity to specify a machine specific configuration file.
 
-       2) elilo-ia32.config or elilo-ia64.conf
+       2) AA[BB[CC]][-ia32|ia64].conf 
+           As of version 3.5, elilo will also look for IPv4 class A,B,C
+           subnet-specific versions of the config file.  This is useful when you
+           want to have a common config file for all machines connected to a
+           particular subnet.
+           
+           For example, if your IP address is 10.0.0.1 (0A000001 in hex), elilo
+           will look first for 0A000001.conf, then 0A0000.conf, then 0A00.conf,
+           and finally 0A.conf.
+
+           Elilo will also try architecture-specific versions of subnet-specific
+           config files first (So for example, on an Itanium system,
+           "0A0000-ia64.conf" will be tried before "0A0000.conf")
+
+       3) elilo-ia32.config or elilo-ia64.conf
           
           Depending on the machine (client side) architecture elilo will try the IA-32 or
           IA-64 file.
@@ -135,7 +149,7 @@ only on two very common cases:
           This distinction between the architectures is useful when the same TFTP server services
           the two types of clients : IA32- and IA-64 machines.
 
-        3) elilo.conf
+        4) elilo.conf
 
   All files use the same format. Elilo will stop at the first match. In case no file is found,
   it will try to download a default kernel file name (vmlinux).
diff --git a/elilo-ia32.efi b/elilo-ia32.efi
deleted file mode 100755 (executable)
index 3f8cd33..0000000
Binary files a/elilo-ia32.efi and /dev/null differ
diff --git a/elilo-ia64.efi b/elilo-ia64.efi
deleted file mode 100755 (executable)
index 6022fed..0000000
Binary files a/elilo-ia64.efi and /dev/null differ
diff --git a/elilo.c b/elilo.c
index 0959c7133295c1a266589920e4f35ffab5ef8f9d..6bdd6bd28a86d781f6451b69f906ac962348b4e0 100644 (file)
--- a/elilo.c
+++ b/elilo.c
@@ -34,6 +34,7 @@
 
 #include "elilo.h"
 #include "vars.h"
+#include "gzip.h"
 
 #include "getopt.h"
 #include "fileops.h"
@@ -84,13 +85,23 @@ do_kernel_load(CHAR16 *kname, kdesc_t *kd)
 }
 
 INTN
-kernel_load(EFI_HANDLE image, CHAR16 *kname, kdesc_t *kd, memdesc_t *imem)
+kernel_load(EFI_HANDLE image, CHAR16 *kname, kdesc_t *kd, memdesc_t *imem, memdesc_t *mmem)
 {
+       CHAR16 kernel[CMDLINE_MAXLEN];
 
+       /*
+        * Do the vm image switch here
+        * if there is "vmm=" then elilo should load image specified
+        * in "vmm=" and then give the "image" to vmm as target kernel image
+        */
+       if (elilo_opt.vmcode[0])
+               StrCpy(kernel, elilo_opt.vmcode);
+       else
+               StrCpy(kernel, kname);
        /*
         * Now let's try to load the kernel !
         */
-       switch(do_kernel_load(kname, kd)) {
+       switch(do_kernel_load(kernel, kd)) {
                case ELILO_LOAD_SUCCESS:
                        break;
 
@@ -101,6 +112,7 @@ kernel_load(EFI_HANDLE image, CHAR16 *kname, kdesc_t *kd, memdesc_t *imem)
                case ELILO_LOAD_ABORTED:
                        /* we drop initrd in case we aborted the load */
                        elilo_opt.initrd[0] = CHAR_NULL;
+                       elilo_opt.vmcode[0] = CHAR_NULL;
 
                        /* will go back to interactive selection */
                        elilo_opt.prompt  = 1; 
@@ -111,33 +123,75 @@ kernel_load(EFI_HANDLE image, CHAR16 *kname, kdesc_t *kd, memdesc_t *imem)
        }
 
        VERB_PRT(3, Print(L"kernel loaded in [0x%lx-0x%lx] entry=0x%lx\n", 
-                         (UINT64)kd->kstart, (UINT64)kd->kend, (UINT64)kd->kentry));
+                         (unsigned long)kd->kstart, (unsigned long)kd->kend, (unsigned long)kd->kentry));
 
        if (elilo_opt.initrd[0]) {
 
                if (sysdeps_initrd_get_addr(kd, imem) == -1) goto exit_error;
 
-               switch(load_initrd(elilo_opt.initrd, imem)) {
+               switch(load_file(elilo_opt.initrd, imem)) {
                        case ELILO_LOAD_SUCCESS:
                                break;
                        case ELILO_LOAD_ERROR:
                                goto exit_error;
                        case ELILO_LOAD_ABORTED:
-                               /* the free_kmem() is the responsibility of the loader */
+                               free_kmem();
+                               /* we drop initrd in case we aborted the load */
+                               elilo_opt.initrd[0] = CHAR_NULL;
+                               elilo_opt.vmcode[0] = CHAR_NULL;
+                               elilo_opt.prompt    = 1; 
+                               elilo_opt.timeout   = ELILO_DEFAULT_TIMEOUT;
+                               elilo_opt.delay     = 0;
+
+                               return ELILO_LOAD_RETRY;
+               }
+       }
+
+       if (elilo_opt.vmcode[0]) {
 
+               mmem->start_addr = 0; /* let the allocator decide */
+
+               switch(load_file(kname, mmem)) {
+                       case ELILO_LOAD_SUCCESS:
+                               break;
+                       case ELILO_LOAD_ERROR:
+                               goto exit_error;
+                       case ELILO_LOAD_ABORTED:
+                               if (imem->start_addr)
+                                       free(imem->start_addr);
+                               free_kmem();
                                /* we drop initrd in case we aborted the load */
                                elilo_opt.initrd[0] = CHAR_NULL;
+                               elilo_opt.vmcode[0] = CHAR_NULL;
                                elilo_opt.prompt    = 1; 
                                elilo_opt.timeout   = ELILO_DEFAULT_TIMEOUT;
                                elilo_opt.delay     = 0;
 
                                return ELILO_LOAD_RETRY;
                }
+
+               /* Test for a compressed image and unzip if found */
+               if (gzip_probe(mmem->start_addr, mmem->size) == 0 &&
+                   gunzip_image(mmem) != ELILO_LOAD_SUCCESS) {
+                       if (imem->start_addr)
+                               free(imem->start_addr);
+                       free(mmem->start_addr);
+                       free_kmem();
+                       /* we drop initrd in case we aborted the load */
+                       elilo_opt.initrd[0] = CHAR_NULL;
+                       elilo_opt.vmcode[0] = CHAR_NULL;
+                       elilo_opt.prompt    = 1; 
+                       elilo_opt.timeout   = ELILO_DEFAULT_TIMEOUT;
+                       elilo_opt.delay     = 0;
+
+                       return ELILO_LOAD_RETRY;
+               }
        }
        return ELILO_LOAD_SUCCESS;
 exit_error:
        free_kmem();
        if (imem->start_addr) free(imem->start_addr);
+       if (mmem->start_addr) free(mmem->start_addr);
 
        return ELILO_LOAD_ERROR;
 }
@@ -152,7 +206,7 @@ main_loop(EFI_HANDLE dev, CHAR16 **argv, INTN argc, INTN index, EFI_HANDLE image
        UINTN cookie;
        EFI_STATUS status = EFI_SUCCESS;
        kdesc_t kd;
-       memdesc_t imem;
+       memdesc_t imem, mmem;
        INTN r;
 
        /*
@@ -164,12 +218,12 @@ main_loop(EFI_HANDLE dev, CHAR16 **argv, INTN argc, INTN index, EFI_HANDLE image
 
        for(;;) {
                kname[0] = cmdline_tmp[0] = cmdline[0] = CHAR_NULL;
-               imem.start_addr = 0; imem.pgcnt = 0;
+               imem.start_addr = 0; imem.pgcnt = 0; imem.size = 0;
                elilo_opt.sys_img_opts = NULL;
 
                if (kernel_chooser(argv, argc, index, kname, cmdline_tmp) == -1) goto exit_error;
 
-               switch (kernel_load(image, kname, &kd, &imem)) {
+               switch (kernel_load(image, kname, &kd, &imem, &mmem)) {
                        case ELILO_LOAD_SUCCESS: 
                                goto do_launch;
                        case ELILO_LOAD_ERROR:
@@ -187,7 +241,7 @@ do_launch:
        close_devices();
 
        /* No console output permitted after create_boot_params()! */
-       if ((bp=create_boot_params(cmdline, &imem, &cookie)) == 0) goto error;
+       if ((bp=create_boot_params(cmdline, &imem, &mmem, &cookie)) == 0) goto error;
 
        /* terminate bootservices */
        status = BS->ExitBootServices(image, cookie);
@@ -221,6 +275,7 @@ elilo_help(VOID)
        Print(L"-v        verbose level(can appear multiple times)\n");
        Print(L"-a        always check for alternate kernel image\n");
        Print(L"-i file   load file as the initial ramdisk\n");
+       Print(L"-m file   load file as additional boot time vmm module\n");
        Print(L"-C file   indicate the config file to use\n");
        Print(L"-P        parse config file only (verify syntax)\n");
        Print(L"-D        enable debug prints\n");
@@ -368,8 +423,8 @@ efi_main (EFI_HANDLE image, EFI_SYSTEM_TABLE *system_tab)
        CHAR16 dpath[FILENAME_MAXLEN];
        CHAR16 *devpath;
 
-       //elilo_opt.verbose=3;
-       //elilo_opt.debug=1;
+       elilo_opt.verbose=0;
+       elilo_opt.debug=0;
 
        /* initialize global variable */
        systab = system_tab;
@@ -491,6 +546,13 @@ efi_main (EFI_HANDLE image, EFI_SYSTEM_TABLE *system_tab)
                                }
                                StrCpy(elilo_opt.initrd, Optarg);
                                break;
+                       case 'm':
+                               if (StrLen(Optarg) >= FILENAME_MAXLEN-1) {
+                                       Print(L"vmm module filename is limited to %d characters\n", FILENAME_MAXLEN);
+                                       goto do_exit;
+                               }
+                               StrCpy(elilo_opt.vmcode, Optarg);
+                               break;
                        case 'C':
                                if (StrLen(Optarg) >= FILENAME_MAXLEN-1) {
                                        Print(L"config filename is limited to %d characters\n", FILENAME_MAXLEN);
@@ -548,23 +610,37 @@ efi_main (EFI_HANDLE image, EFI_SYSTEM_TABLE *system_tab)
        /*
         * set per fileops defaults files for configuration and kernel
         */
-       fops_setdefaults(elilo_opt.default_config, elilo_opt.default_kernel, FILENAME_MAXLEN, devpath);
+       fops_setdefaults(elilo_opt.default_configs, elilo_opt.default_kernel, FILENAME_MAXLEN, devpath);
 
        /*
         * XXX: won't be visible if verbose not required from command line
         */
        VERB_PRT(2,Print(L"Default config: %s\nDefault_kernel: %s\n",
-                       elilo_opt.default_config,elilo_opt.default_kernel));
+                       elilo_opt.default_configs[0].fname, elilo_opt.default_kernel));
        /*
         * use default config file if not specified by user
         */
-       ptr = elilo_opt.config[0] == CHAR_NULL ?  (retry=1,elilo_opt.default_config) : (retry=0,elilo_opt.config);
+       ptr = elilo_opt.config[0] == CHAR_NULL ?  (retry=1,elilo_opt.default_configs[0].fname) : (retry=0,elilo_opt.config);
 
        /*
         * parse config file (verbose becomes visible if set)
         */
-       ret = read_config(ptr, retry);
-       Print(L"read_config=%r\n", ret);
+       ret = read_config(ptr);
+       VERB_PRT(1,Print(L"read_config=%r\n", ret));
+
+        /* Only try the default config filenames if user did not specify a
+         * config filename on the command line */
+        if (elilo_opt.config[0] == CHAR_NULL) {
+                while ((ret != EFI_SUCCESS) &&
+                       (retry < MAX_DEFAULT_CONFIGS) &&
+                       (elilo_opt.default_configs[retry].fname[0] != CHAR_NULL)) {
+
+                        ptr = elilo_opt.default_configs[retry].fname;
+                        ret = read_config(ptr);
+                        VERB_PRT(1,Print(L"read_config=%r\n", ret));
+                        retry += 1;
+                }
+        }
        /*
         * when the config file is not found, we fail only if:
         *      - the user did not specified interactive mode
@@ -593,11 +669,19 @@ efi_main (EFI_HANDLE image, EFI_SYSTEM_TABLE *system_tab)
         * if there was an error when parsing the config file, then
         * we force interactive mode to give a chance to the user.
         * We also clear the error. 
-        */
-       if (ret && argc == 1) {
-               Print(L"forcing interactive mode because of errors\n");
+         */
+       if (ret != EFI_SUCCESS) {
+               Print(L"forcing interactive mode due to config file error(s)\n");
                elilo_opt.prompt = 1;
        }
+        /*
+        * However, if the user specified a kernel on the command line
+        * then we don't go to interactive mode, even if there was an option in
+         * the config file telling us to do so.
+        */
+       if (argc > Optind) {
+            elilo_opt.prompt = 0;
+        }
 
        /*
         * If EDD30 EFI variable was not set to TRUE (or not defined), we
@@ -613,13 +697,6 @@ efi_main (EFI_HANDLE image, EFI_SYSTEM_TABLE *system_tab)
 
        ret = EFI_LOAD_ERROR;
 
-       /*
-        * if the user specified a kernel on the command line
-        * then we don't go to interactive mode even if it
-        * was set in the config file or set because of an
-        * error parsing the config file.
-        */
-       if (argc > Optind) elilo_opt.prompt = 0;
 
 
        /* set default timeout if going interactive */
diff --git a/elilo.h b/elilo.h
index 9d2861796dcfd0a0d9f183a6a0c2bc267aee4804..74f740d0082f31c360b6f6802c742dc0a5cd4425 100644 (file)
--- a/elilo.h
+++ b/elilo.h
 #define CMDLINE_MAXLEN         512 /* needed by ia32 */
 #define FILENAME_MAXLEN                256
 #define MAX_ARGS               256
+/* Just pick an arbitrary number that's high enough for now :o) */
+#define MAX_DEFAULT_CONFIGS     16
 
 typedef struct {
        UINT8 nothing_yet;
 } image_opt_t;
 
+typedef struct config_file {
+       CHAR16 fname[FILENAME_MAXLEN];
+} config_file_t;
+
 typedef struct {
        /*
         * list of options controllable from both the command line
@@ -75,6 +81,7 @@ typedef struct {
        UINTN delay;            /* delay before booting the image */
        UINTN verbose;          /* verbosity level [1-5] */
        CHAR16 initrd[FILENAME_MAXLEN];         /* name of file for initial ramdisk */
+       CHAR16 vmcode[FILENAME_MAXLEN]; /* name of file for boot time module*/
        UINT8 delay_set;        /* mark whether or not delay was specified on cmdline */
        UINT8 edd30_on;         /* true is EDD30 variable is TRUE */
        UINT8 edd30_no_force;   /* don't force EDD30 variable to true */
@@ -91,7 +98,8 @@ typedef struct {
        sys_img_options_t *sys_img_opts;        /* architecture depdendent per image options */
 
        CHAR16 default_kernel[FILENAME_MAXLEN];
-       CHAR16 default_config[FILENAME_MAXLEN];
+       /* CHAR16 default_config[FILENAME_MAXLEN]; */
+        config_file_t default_configs[MAX_DEFAULT_CONFIGS];
 
        CHAR16 config[FILENAME_MAXLEN];         /* name of config file */
        CHAR16 chooser[FILENAME_MAXLEN];        /* image chooser to use */
@@ -105,6 +113,7 @@ extern EFI_SYSTEM_TABLE *systab;
 typedef struct {
        VOID    *start_addr;
        UINTN   pgcnt;
+       UINTN   size;
 } memdesc_t;
 
 typedef struct {
@@ -160,9 +169,9 @@ extern VOID ascii2U(CHAR8 *, CHAR16 *, UINTN);
 extern VOID U2ascii(CHAR16 *, CHAR8 *, UINTN);
 
 /* from config.c (more in config.h) */
-extern EFI_STATUS read_config(CHAR16 *, INTN retry);
+extern EFI_STATUS read_config(CHAR16 *);
 extern VOID print_config_options(VOID);
-extern INTN find_label(CHAR16 *, CHAR16 *, CHAR16 *, CHAR16 *);
+extern INTN find_label(CHAR16 *, CHAR16 *, CHAR16 *, CHAR16 *, CHAR16 *);
 extern VOID print_label_list(VOID);
 extern INTN config_init(VOID);
 extern CHAR16 *get_message_filename(INTN which);
@@ -171,13 +180,13 @@ extern VOID *get_next_description(VOID *prev, CHAR16 **label, CHAR16 **descripti
 extern CHAR16 *get_config_file(VOID);
 
 /* from initrd.c */
-extern INTN load_initrd(CHAR16 *, memdesc_t *);
+extern INTN load_file(CHAR16 *, memdesc_t *);
 
 /* from alternate.c */
 extern INTN alternate_kernel(CHAR16 *, INTN);
 
 /* from bootparams.c */
-extern VOID *create_boot_params (CHAR16 *, memdesc_t *, UINTN *);
+extern VOID *create_boot_params (CHAR16 *, memdesc_t *, memdesc_t *, UINTN *);
 extern VOID free_boot_params(VOID *bp);
 
 /*
@@ -185,7 +194,7 @@ extern VOID free_boot_params(VOID *bp);
  */
 
 
-extern INTN sysdeps_create_boot_params(boot_params_t *, CHAR8 *, memdesc_t *, UINTN *);
+extern INTN sysdeps_create_boot_params(boot_params_t *, CHAR8 *, memdesc_t *, memdesc_t *, UINTN *);
 extern VOID sysdeps_free_boot_params(boot_params_t *);
 extern INTN sysdeps_init(EFI_HANDLE dev);
 extern INTN sysdeps_initrd_get_addr(kdesc_t *, memdesc_t *);
index 674fc5c4100f20db1abd3d523f2e9eff609e3cc4..85f348527a5591d9772b819da961b7e7e37baa9d 100644 (file)
--- a/fileops.c
+++ b/fileops.c
@@ -345,12 +345,37 @@ fops_seek(fops_fd_t fd, UINT64 newpos)
 }
 
 EFI_STATUS
-fops_setdefaults(CHAR16 *config, CHAR16 *kname, UINTN maxlen, CHAR16 *devpath)
+fops_setdefaults(struct config_file *defconf, CHAR16 *kname, UINTN maxlen, CHAR16 *devpath)
 {
+    INTN i;
+
+/*
+ * The first default config file is architecture dependent. This is useful
+ * in case of network booting where the server is used for both types of
+ * architectures.
+ */
+#if defined(CONFIG_ia64)
+#define FILEOPS_ARCH_DEFAULT_CONFIG    L"elilo-ia64.conf"
+#elif defined (CONFIG_ia32)
+#define FILEOPS_ARCH_DEFAULT_CONFIG    L"elilo-ia32.conf"
+#else
+#error "You need to specfy your default arch config file"
+#endif
+
+/* 
+ * last resort config file. Common to all architectures
+ */
+#define FILEOPS_DEFAULT_CONFIG L"elilo.conf"
+
 #define FILEOPS_DEFAULT_KERNEL         L"vmlinux"
-#define FILEOPS_DEFAULT_CONFIG         L"elilo.conf"
 
-       if (config == NULL || kname == NULL) return EFI_INVALID_PARAMETER;
+#ifdef ELILO_DEBUG
+       if (defconf == NULL || kname == NULL) return EFI_INVALID_PARAMETER;
+#endif
+
+        for (i=0; i<MAX_DEFAULT_CONFIGS; i++) {
+            defconf[i].fname[0] = CHAR_NULL;
+        }
 
        if (boot_dev == NULL || boot_dev->fops == NULL) {
                if (boot_dev == NULL) 
@@ -360,13 +385,30 @@ fops_setdefaults(CHAR16 *config, CHAR16 *kname, UINTN maxlen, CHAR16 *devpath)
 
                Print(L"Using builtin defaults for kernel and config file\n");
 
-               StrnCpy(config, FILEOPS_DEFAULT_CONFIG, maxlen-1);
                StrnCpy(kname, FILEOPS_DEFAULT_KERNEL, maxlen-1);
-
-               return EFI_UNSUPPORTED;
        }
-       
-       return boot_dev->fops->setdefaults(boot_dev->fops->intf, config, kname, maxlen, devpath);
+        else {
+                boot_dev->fops->setdefaults(boot_dev->fops->intf, defconf, kname, maxlen, devpath);
+        }
+        i=0; while (i<MAX_DEFAULT_CONFIGS && defconf[i].fname[0] != CHAR_NULL) i += 1;
+#ifdef ELILO_DEBUG
+        if ((i+3) >= MAX_DEFAULT_CONFIGS) {
+            Print(L"ERROR: i = %d, MAX_DEFAULT_CONFIGS is not large enough\n", i);
+            return EFI_INVALID_PARAMETER;
+        }
+#endif
+        StrnCpy(defconf[i].fname, FILEOPS_ARCH_DEFAULT_CONFIG, maxlen-1);
+        StrnCpy(defconf[i+1].fname, FILEOPS_DEFAULT_CONFIG, maxlen-1);
+
+#ifdef ELILO_DEBUG
+        VERB_PRT(3,Print(L"Default config filename list:\n"));
+        for (i=0; i<MAX_DEFAULT_CONFIGS; i++) {
+                if (defconf[i].fname[0] == CHAR_NULL) { break; }
+                        VERB_PRT(3,Print(L"\t%s\n", defconf[i].fname));
+        }
+#endif
+        
+       return EFI_SUCCESS;
 }
 
 EFI_STATUS
index 0150f3588bf0536e33bcea6ca905d7bd13b0b8a3..c4ced0baad69c87d5c7c1b886648b11b5c9dac01 100644 (file)
--- a/fileops.h
+++ b/fileops.h
  */
 typedef UINTN  fops_fd_t;
 
+/* Forward declaration: */
+struct config_file;
+
 extern EFI_STATUS fops_open(CHAR16 *name, fops_fd_t *fd);
 extern EFI_STATUS fops_read(fops_fd_t fd,VOID *buf, UINTN *size);
 extern EFI_STATUS fops_close(fops_fd_t fd);
 extern EFI_STATUS fops_infosize(fops_fd_t fd, UINT64 *size);
 extern EFI_STATUS fops_seek(fops_fd_t fd, UINT64 newpos);
-extern EFI_STATUS fops_setdefaults(CHAR16 *config, CHAR16 *kname, UINTN maxlen, CHAR16 *devpath);
+extern EFI_STATUS fops_setdefaults(struct config_file *defconf, CHAR16 *kname, UINTN maxlen, CHAR16 *devpath);
 extern EFI_STATUS fops_getdefault_path(CHAR16 *path, UINTN maxlen);
 extern CHAR16     *fops_bootdev_name(VOID);
 
@@ -46,12 +49,13 @@ extern CHAR16     *fops_bootdev_name(VOID);
 /*
  * fileops interface used by underlying filesystems layer
  */
+
 typedef EFI_STATUS (*fops_open_t)(VOID *intf, CHAR16 *name, fops_fd_t *fd);
 typedef EFI_STATUS (*fops_read_t)(VOID *intf, fops_fd_t fd, VOID *buf, UINTN *size);
 typedef        EFI_STATUS (*fops_close_t)(VOID *intf, fops_fd_t fd);
 typedef        EFI_STATUS (*fops_infosize_t)(VOID *intf, fops_fd_t fd, UINT64 *size);
 typedef        EFI_STATUS (*fops_seek_t)(VOID *intf, fops_fd_t fd, UINT64 newpos);
-typedef        EFI_STATUS (*fops_setdefaults_t)(VOID *intf, CHAR16 *config, CHAR16 *kname, UINTN maxlen, CHAR16 *devpath);
+typedef        EFI_STATUS (*fops_setdefaults_t)(VOID *intf, struct config_file *defconfs, CHAR16 *kname, UINTN maxlen, CHAR16 *devpath);
 typedef        EFI_STATUS (*fops_getdefault_path_t)(CHAR16 *path, UINTN maxlen);
 
 typedef struct {
index 73aa13df3884f6a2e6eec27d6ec4243fd5a839a4..e15b172a346b659d079e7be60f80f0ec25ca0361 100644 (file)
@@ -99,13 +99,13 @@ set_default_path(CHAR16 *sptr)
 #define LOCALFS_DEFAULT_KERNEL L"vmlinux"
 #define LOCALFS_DEFAULT_CONFIG L"elilo.conf"
 static EFI_STATUS
-localfs_setdefaults(VOID *this, CHAR16 *config, CHAR16 *kname, UINTN maxlen, CHAR16 *devpath)
+localfs_setdefaults(VOID *this, config_file_t *config, CHAR16 *kname, UINTN maxlen, CHAR16 *devpath)
 {
        StrnCpy(kname, LOCALFS_DEFAULT_KERNEL, maxlen-1);
        kname[maxlen-1] = CHAR_NULL;
 
-       StrnCpy(config, LOCALFS_DEFAULT_CONFIG, maxlen-1);
-       config[maxlen-1] = CHAR_NULL;
+       StrnCpy(config[0].fname, LOCALFS_DEFAULT_CONFIG, maxlen-1);
+       config[0].fname[maxlen-1] = CHAR_NULL;
 
        set_default_path(devpath);
 
index 757fc8b8f3ba2b0f39b5d22e7831f822a2279e1a..5de36298256574621cb70f45bb58b360c8ac74fa 100644 (file)
@@ -117,7 +117,7 @@ netfs_set_default_path(netfs_interface_t *netfs, netfs_info_t *info)
 }
 
 static EFI_STATUS
-netfs_setdefaults(VOID *intf, CHAR16 *config, CHAR16 *kname, UINTN maxlen, CHAR16 *devpath)
+netfs_setdefaults(VOID *intf, config_file_t *config, CHAR16 *kname, UINTN maxlen, CHAR16 *devpath)
 {
        netfs_interface_t *netfs = (netfs_interface_t *)intf;
        netfs_info_t info;
@@ -149,10 +149,10 @@ netfs_setdefaults(VOID *intf, CHAR16 *config, CHAR16 *kname, UINTN maxlen, CHAR1
        set_var(VAR_NETFS_DOMAINAME, info.domainame);
 
        if (info.using_pxe) {
-               status = netfs->netfs_query_layer(netfs, 0, NETFS_CONFIG_LAYER, maxlen, config);
+               status = netfs->netfs_query_layer(netfs, 0, NETFS_CONFIG_LAYER, maxlen, config[0].fname);
                if (EFI_ERROR(status)) {
-                       StrnCpy(config, NETFS_DEFAULT_CONFIG, maxlen-1);
-                       config[maxlen-1] = CHAR_NULL;
+                       StrnCpy(config[0].fname, NETFS_DEFAULT_CONFIG, maxlen-1);
+                       config[0].fname[maxlen-1] = CHAR_NULL;
                }
 
                status = netfs->netfs_query_layer(netfs, 0, NETFS_KERNEL_LAYER, maxlen, kname);
@@ -162,21 +162,44 @@ netfs_setdefaults(VOID *intf, CHAR16 *config, CHAR16 *kname, UINTN maxlen, CHAR1
                }
        } else {
 #ifdef ENABLE_MACHINE_SPECIFIC_NETCONFIG
+
+#  if defined(CONFIG_ia64)
+#    define CONFIG_ARCH_EXTENSION L"-ia64.conf\0"
+#  elif defined (CONFIG_ia32)
+#    define CONFIG_ARCH_EXTENSION L"-ia64.conf\0"
+#  else
+#    error "You need to specfy your default arch config file"
+#  endif            
+
+#  define CONFIG_EXTENSION L".conf\0"
                /*
-                * will try a machine specific file first.
-                * the file is constructed based on the IP(v4) address
+                * will try machine/subnet specific files first.
+                * the filenames are constructed based on the IP(v4) address
                 */
-               convert_ip2hex(ipaddr, m, config);
-
-               config[8]  = L'.';
-               config[9]  = L'c';
-               config[10] = L'o';
-               config[11] = L'n';
-               config[12] = L'f';
-               config[13] = CHAR_NULL;
+               convert_ip2hex(ipaddr, m, str);
+               StrnCpy(config[0].fname, str, maxlen-1);
+               StrnCpy(config[0].fname+8, CONFIG_EXTENSION, 6);
+
+               StrnCpy(config[1].fname, str, maxlen-1);
+               StrnCpy(config[1].fname+6, CONFIG_ARCH_EXTENSION, 11);
+
+               StrnCpy(config[2].fname, str, maxlen-1);
+               StrnCpy(config[2].fname+6, CONFIG_EXTENSION, 6);
+
+               StrnCpy(config[3].fname, str, maxlen-1);
+               StrnCpy(config[3].fname+4, CONFIG_ARCH_EXTENSION, 11);
+
+               StrnCpy(config[4].fname, str, maxlen-1);
+               StrnCpy(config[4].fname+4, CONFIG_EXTENSION, 6);
+                
+               StrnCpy(config[5].fname, str, maxlen-1);
+               StrnCpy(config[5].fname+2, CONFIG_ARCH_EXTENSION, 11);
+
+               StrnCpy(config[6].fname, str, maxlen-1);
+               StrnCpy(config[6].fname+2, CONFIG_EXTENSION, 6);
 #else
-               StrnCpy(config, NETFS_DEFAULT_CONFIG, maxlen-1);
-               config[maxlen-1] = CHAR_NULL;
+               StrnCpy(config[0].fname, NETFS_DEFAULT_CONFIG, maxlen-1);
+               config[0].fname[maxlen-1] = CHAR_NULL;
 #endif
                StrnCpy(kname, NETFS_DEFAULT_KERNEL, maxlen-1);
                kname[maxlen-1] = CHAR_NULL;
diff --git a/gnu-efi-3.0a-ia32.patch b/gnu-efi-3.0a-ia32.patch
deleted file mode 100644 (file)
index 6e3baf1..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-diff -urN gnu-efi-3.0a/gnuefi/elf_ia32_efi.lds gnu-efi-3.0a-ia32/gnuefi/elf_ia32_efi.lds
---- gnu-efi-3.0a/gnuefi/elf_ia32_efi.lds       2002-02-22 15:43:28.000000000 -0800
-+++ gnu-efi-3.0a-ia32/gnuefi/elf_ia32_efi.lds  2003-08-21 13:36:51.000000000 -0700
-@@ -17,6 +17,7 @@
-    *(.rodata*)
-    *(.data)
-    *(.data1)
-+   *(.data.*)
-    *(.sdata)
-    *(.got.plt)
-    *(.got)
-@@ -34,6 +35,7 @@
-   .rel :
-   {
-     *(.rel.data)
-+    *(.rel.data.*)
-     *(.rel.got)
-     *(.rel.stab)
-   }
diff --git a/gunzip.c b/gunzip.c
new file mode 100644 (file)
index 0000000..18fb11f
--- /dev/null
+++ b/gunzip.c
@@ -0,0 +1,224 @@
+/*
+ *  Copyright (C) 2005 Hewlett-Packard Development Company, L.P.
+ *     Contributed by Alex Williamson <alex.williamson@hp.com>
+ *
+ *  Copyright (C) 2001-2003 Hewlett-Packard Co.
+ *     Contributed by Stephane Eranian <eranian@hpl.hp.com>
+ *
+ *  Copyright (C) 2001 Silicon Graphics, Inc.
+ *      Contributed by Brent Casavant <bcasavan@sgi.com>
+ *
+ * This file is part of the ELILO, the EFI Linux boot loader.
+ *
+ *  ELILO 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 2, or (at your option)
+ *  any later version.
+ *
+ *  ELILO 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 ELILO; see the file COPYING.  If not, write to the Free
+ *  Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ *  02111-1307, USA.
+ *
+ * Please check out the elilo.txt for complete documentation on how
+ * to use this program.
+ */
+
+#include <efi.h>
+#include <efilib.h>
+
+#include "elilo.h"
+
+#include "gzip.h"
+
+#define LD_NAME L"gunzip"
+
+#define memzero(s, n)  Memset((VOID *)(s), 0, (n))
+#define memcpy(a,b,n)  Memcpy((VOID *)(a),(b),(n))
+
+/* size of output buffer */
+#define WSIZE 0x8000           /* Window size must be at least 32k, */
+                               /* and a power of two */
+/*
+ * gzip declarations
+ */
+#define OF(args)  args
+#define FUNC_STATIC static
+
+typedef unsigned char  uch;
+typedef unsigned short ush;
+typedef unsigned long  ulg;
+
+/*
+ * static parameters to gzip helper functions
+ * we cannot use paramters because API was not
+ * designed that way
+ */
+static uch *inbuf;             /* input buffer (compressed data) */
+static uch *window;                    /* output buffer (uncompressed data) */
+
+static VOID *outbuf;
+unsigned char *outptr;
+static unsigned long outsize;
+
+static unsigned inptr  = 0;   /* index of next byte to be processed in inbuf */
+static unsigned outcnt = 0;  /* bytes in output buffer */
+
+#define get_byte()  inbuf[inptr++]
+
+/* Diagnostic functions */
+#ifdef INFLATE_DEBUG
+#  define Assert(cond,msg) {if(!(cond)) error(msg);}
+int stderr;
+#  define Trace(x) Print(L"line %d:\n", __LINE__);
+#  define Tracev(x) {if (verbose) Print(L"line %d:\n", __LINE__) ;}
+#  define Tracevv(x) {if (verbose>1) Print(L"line %d:\n", __LINE__)  ;}
+#  define Tracec(c,x) {if (verbose && (c))  Print(L"line %d:\n", __LINE__) ;}
+#  define Tracecv(c,x) {if (verbose>1 && (c))  Print(L"line %d:\n", __LINE__) ;}
+#else
+#  define Assert(cond,msg)
+#  define Trace(x)
+#  define Tracev(x)
+#  define Tracevv(x)
+#  define Tracec(c,x)
+#  define Tracecv(c,x)
+#endif
+
+static void flush_window(void);
+static void error(char *m);
+static long bytes_out;
+
+static void error(char *m);
+
+#define gzip_malloc(size) (void *)alloc(size, 0)
+#define gzip_free(where) free(where)
+
+#include "inflate.c"
+
+/*
+ * Run a set of bytes through the crc shift register.  If s is a NULL
+ * pointer, then initialize the crc shift register contents instead.
+ * Return the current crc in either case.
+ *
+ * Input:
+ *     S       pointer to bytes to pump through.
+ *     N       number of bytes in S[].
+ */
+static void
+updcrc(unsigned char *s, unsigned n)
+{
+       register unsigned long c;
+       /* crc is defined in inflate.c */
+
+       c = crc;
+       while (n--) {
+               c = crc_32_tab[((int)c ^ (*s++)) & 0xff] ^ (c >> 8);
+       }
+       crc = c;
+       return;
+}
+
+/*
+ * Clear input and output buffers
+ */
+static void
+clear_bufs(void)
+{
+       outcnt = 0;
+       inptr = 0;
+}
+
+/*
+ * Write the output window window[0..outcnt-1] holding uncompressed
+ * data and update crc.
+ */
+void
+flush_window(void)
+{
+       /*
+        * We'll end up relying on the CRC check and size check failing
+        * if there's actually more data than we expect.
+        */
+       if (!outcnt || bytes_out + outcnt > outsize)
+               return;
+
+       updcrc(window, outcnt);
+
+       Memcpy(outptr, window, outcnt);
+       outptr += outcnt;
+       bytes_out += outcnt;
+
+       outcnt = 0;
+}
+
+static void
+error(char *x)
+{
+       ERR_PRT((L"%s : %a", LD_NAME, x));
+       /* will eventually exit with error from gunzip() */
+}
+
+static INT32
+decompress(VOID)
+{
+       INT32 ret;
+
+       clear_bufs();
+       makecrc();
+       Print(L"Uncompressing... ");
+       ret = gunzip();
+       if (ret == 0) Print(L"done\n");
+       return ret == 0 ? 0 : -1;
+}
+
+int
+gunzip_image(memdesc_t *image)
+{
+       UINTN pgcnt;
+
+       inbuf = image->start_addr;
+
+       /* 
+        * Last 4 bytes of gzip'd image indicates the uncompressed size
+        */
+       outsize = inbuf[image->size - 1] << 24 | inbuf[image->size - 2] << 16 |
+                 inbuf[image->size - 3] << 8 | inbuf[image->size - 4];
+
+       pgcnt = EFI_SIZE_TO_PAGES(outsize);
+
+       outbuf = alloc_pages(pgcnt, EfiLoaderData, AllocateAnyPages, 0);
+       if (outbuf == NULL) {
+               ERR_PRT((L"%s : allocate output buffer failed\n", LD_NAME));
+               return -1;
+       }
+       outptr = outbuf;
+
+       window = (void *)alloc(WSIZE, 0);
+       if (window == NULL) {
+               ERR_PRT((L"%s : allocate output window failed\n", LD_NAME));
+               free(outbuf);
+               return -1;
+       }
+
+       bytes_out  = 0;
+
+       if (decompress() != 0) {
+               free(window);
+               free(outbuf);
+               return ELILO_LOAD_ERROR;
+       }
+
+       free(window);
+       free(image->start_addr);
+
+       image->start_addr = outbuf;
+       image->size = outsize;
+       image->pgcnt = pgcnt;
+
+       return ELILO_LOAD_SUCCESS;
+}
diff --git a/gzip.h b/gzip.h
new file mode 100644 (file)
index 0000000..88b53f6
--- /dev/null
+++ b/gzip.h
@@ -0,0 +1,67 @@
+/*
+ *  Copyright (C) 2001-2003 Hewlett-Packard Co.
+ *     Contributed by Stephane Eranian <eranian@hpl.hp.com>
+ *
+ * This file is part of the ELILO, the EFI Linux boot loader.
+ *
+ *  ELILO 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 2, or (at your option)
+ *  any later version.
+ *
+ *  ELILO 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 ELILO; see the file COPYING.  If not, write to the Free
+ *  Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ *  02111-1307, USA.
+ *
+ * Please check out the elilo.txt for complete documentation on how
+ * to use this program.
+ */
+
+#ifndef __GZIP_H__
+#define __GZIP_H__
+
+int gunzip_image(memdesc_t *);
+int gunzip_kernel(fops_fd_t, kdesc_t *);
+
+/* gzip flag byte */
+#define ASCII_FLAG   0x01 /* bit 0 set: file probably ASCII text */
+#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
+#define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
+#define ORIG_NAME    0x08 /* bit 3 set: original file name present */
+#define COMMENT      0x10 /* bit 4 set: file comment present */
+#define ENCRYPTED    0x20 /* bit 5 set: file is encrypted */
+#define RESERVED     0xC0 /* bit 6,7:   reserved */
+
+/*
+ * check for valid gzip signature
+ * return:
+ *      0 : valid gzip archive
+ *      -1: invalid gzip archive
+ */
+static inline int
+gzip_probe(unsigned char *buf, unsigned long size)
+{
+    if (size < 4) return -1;
+
+    if (buf[0] != 037 ||
+        ((buf[1] != 0213) && (buf[1] != 0236))) return -1;
+
+    /* We only support method #8, DEFLATED */
+    if (buf[2] != 8) return -1;
+    
+    if ((buf[3] & ENCRYPTED) != 0) return -1;
+
+    if ((buf[3] & CONTINUATION) != 0) return -1;
+
+    if ((buf[3] & RESERVED) != 0) return -1;
+
+    return 0;
+}
+
+#endif /* __GZIP_H__ */
index 1b1c16ca203b495f59cace57302f0b32c6193910..353ae6791dffb98d8803a5ee148d313d01e09fee 100644 (file)
@@ -28,7 +28,7 @@ include ../Make.rules
 
 TOPDIR=$(CDIR)/..
 
-FILES=system.o config.o
+FILES=system.o config.o bzimage.o plain_loader.o gzip_loader.o gzip.o
 
 TARGET=sysdeps.o
 
diff --git a/ia32/bzimage.c b/ia32/bzimage.c
new file mode 100644 (file)
index 0000000..aac1d37
--- /dev/null
@@ -0,0 +1,224 @@
+/*
+ *  Copyright (C) 2001-2003 Hewlett-Packard Co.
+ *     Contributed by Stephane Eranian <eranian@hpl.hp.com>
+ *     Contributed by Mike Johnston <johnston@intel.com>
+ *     Contributed by Chris Ahna <christopher.j.ahna@intel.com>
+ *
+ * This file is part of the ELILO, the EFI Linux boot loader.
+ *
+ *  ELILO 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 2, or (at your option)
+ *  any later version.
+ *
+ *  ELILO 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 ELILO; see the file COPYING.  If not, write to the Free
+ *  Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ *  02111-1307, USA.
+ *
+ * Please check out the elilo.txt for complete documentation on how
+ * to use this program.
+ */
+
+#include <efi.h>
+#include <efilib.h>
+
+#include "elilo.h"
+#include "loader.h"
+
+boot_params_t *param_start = NULL;
+UINTN param_size = 0;
+
+UINTN kernel_size = 0x200000;  /* 2M (largest x86 bzImage kernel image) */
+
+static INTN
+bzImage_probe(CHAR16 *kname)
+{
+       EFI_STATUS efi_status;
+       UINTN size;
+       fops_fd_t fd;
+       UINT8 bootsect[512];
+
+       DBG_PRT((L"probe_bzImage_boot()\n"));
+
+       if (!kname) {
+               ERR_PRT((L"kname == %xh", kname));
+               free_kmem();
+               return -1;
+       }
+
+       /* 
+        * Open kernel image. 
+        */
+       DBG_PRT((L"opening %s...\n", kname));
+
+       efi_status = fops_open(kname, &fd);
+       if (EFI_ERROR(efi_status)) {
+               ERR_PRT((L"Could not open %s.", kname));
+               free_kmem();
+               return -1;
+       }
+       /*
+        * Read boot sector.
+        */
+
+       DBG_PRT((L"\nreading boot sector...\n"));
+
+       size = sizeof bootsect;
+       efi_status = fops_read(fd, bootsect, &size);
+       if (EFI_ERROR(efi_status) || size != sizeof bootsect) {
+               ERR_PRT((L"Could not read boot sector from %s.", kname));
+               fops_close(fd);
+               free_kmem();
+               return -1;
+       }
+       /*
+        * Verify boot sector signature.
+        */
+
+       if (bootsect[0x1FE] != 0x55 || bootsect[0x1FF] != 0xAA) {
+               ERR_PRT((L"%s is not a bzImage kernel image.\n", kname));
+               fops_close(fd);
+               free_kmem();
+               return -1;
+       }
+       /*
+        * Check for out of range setup data size.
+        * Will almost always be 7, but we will accept 1 to 64.
+        */
+
+       DBG_PRT((L"bootsect[1F1h] == %d setup sectors\n", bootsect[0x1F1]));
+
+       if (bootsect[0x1F1] < 1 || bootsect[0x1F1] > 64) {
+               ERR_PRT((L"%s is not a valid bzImage kernel image.",
+                       kname));
+               fops_close(fd);
+               free_kmem();
+               return -1;
+       }
+       /*
+        * Allocate and read setup data.
+        */
+
+       DBG_PRT((L"reading setup data...\n"));
+
+       param_size = (bootsect[0x1F1] + 1) * 512;
+       param_start = alloc(param_size, EfiLoaderData);
+
+       DBG_PRT((L"param_size=%d param_start=%x", param_size, param_start));
+
+       if (!param_start) {
+               ERR_PRT((L"Could not allocate %d bytes of setup data.",
+                       param_size));
+               fops_close(fd);
+               free_kmem();
+               return -1;
+       }
+
+       CopyMem(param_start, bootsect, sizeof bootsect);
+
+       size = param_size - 512;
+       efi_status = fops_read(fd, ((UINT8 *)param_start) + 512, &size);
+
+       if (EFI_ERROR(efi_status) || size != param_size - 512) {
+               ERR_PRT((L"Could not read %d bytes of setup data.",
+                       param_size - 512));
+               free(param_start);
+               param_start = NULL;
+               param_size = 0;
+               fops_close(fd);
+               free_kmem();
+               return -1;
+       }
+       /*
+        * Check for setup data signature.
+        */
+
+       { 
+               UINT8 *c = ((UINT8 *)param_start)+514;
+               DBG_PRT((L"param_start(c=%x): %c-%c-%c-%c", 
+                       c, (CHAR16)c[0],(CHAR16) c[1], (CHAR16)c[2], (CHAR16)c[3]));
+       }
+       if (CompareMem(((UINT8 *)param_start) + 514, "HdrS", 4)) {
+               ERR_PRT((L"%s does not have a setup signature.",
+                       kname));
+               free(param_start);
+               param_start = NULL;
+               param_size = 0;
+               fops_close(fd);
+               free_kmem();
+               return -1;
+       }
+       /*
+        * Allocate memory for kernel.
+        */
+
+       if (alloc_kmem(kernel_start, EFI_SIZE_TO_PAGES(kernel_size))) {
+               ERR_PRT((L"Could not allocate kernel memory."));
+               return -1;
+       } else {
+               VERB_PRT(3, Print(L"kernel_start: 0x%x  kernel_size: %d\n", 
+                       kernel_start, kernel_size));
+       }
+       /*
+        * Now read the rest of the kernel image into memory.
+        */
+
+       DBG_PRT((L"reading kernel image...\n"));
+
+       size = kernel_size;
+       efi_status = fops_read(fd, kernel_start, &size);
+       if (EFI_ERROR(efi_status) || size < 0x10000) {
+               ERR_PRT((L"Error reading kernel image %s.", kname));
+               free(param_start);
+               param_start = NULL;
+               param_size = 0;
+               fops_close(fd);
+               free_kmem();
+               return -1;
+       }
+
+       DBG_PRT((L"kernel image read:  %d bytes, %d Kbytes\n", size, size / 1024));
+
+       /*
+        * Boot sector, setup data and kernel image loaded.
+        */
+
+       fops_close(fd);
+       return 0;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+static INTN
+bzImage_load(CHAR16 *kname, kdesc_t *kd)
+{
+       DBG_PRT((L"load_bzImage_boot()\n"));
+
+       if (!kname || !kd) {
+               ERR_PRT((L"kname=0x%x  kd=0x%x", kname, kd));
+               free(param_start);
+               param_start = NULL;
+               param_size = 0;
+               free_kmem();
+               return -1;
+       }
+       kd->kstart = kd->kentry = kernel_start;
+       kd->kend = ((UINT8 *)kd->kstart) + kernel_size;
+
+       DBG_PRT((L"kstart=0x%x  kentry=0x%x  kend=0x%x\n", kd->kstart, kd->kentry, kd->kend));
+
+       return 0;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+loader_ops_t bzimage_loader = {
+       NULL,
+       L"bzImage_loader",
+       &bzImage_probe,
+       &bzImage_load
+};
diff --git a/ia32/gzip.c b/ia32/gzip.c
new file mode 100644 (file)
index 0000000..fff5f6d
--- /dev/null
@@ -0,0 +1,554 @@
+/*
+ *  Copyright (C) 2001-2002 Hewlett-Packard Co.
+ *     Contributed by Stephane Eranian <eranian@hpl.hp.com>
+ *
+ *  Copyright (C) 2001 Silicon Graphics, Inc.
+ *      Contributed by Brent Casavant <bcasavan@sgi.com>
+ *
+ * This file is part of the ELILO, the EFI Linux boot loader.
+ *
+ *  ELILO 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 2, or (at your option)
+ *  any later version.
+ *
+ *  ELILO 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 ELILO; see the file COPYING.  If not, write to the Free
+ *  Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ *  02111-1307, USA.
+ *
+ * Please check out the elilo.txt for complete documentation on how
+ * to use this program.
+ */
+
+#include <efi.h>
+#include <efilib.h>
+
+#include "elf.h"
+#include "elilo.h"
+#include "gzip.h"
+#include "private.h"
+
+#define LD_NAME L"gzip_ia32"
+
+#define memzero(s, n)  Memset((VOID *)(s), 0, (n))
+#define memcpy(a,b,n)  Memcpy((VOID *)(a),(b),(n))
+
+/* size of output buffer */
+#define WSIZE 0x8000           /* Window size must be at least 32k, */
+                               /* and a power of two */
+/* size of input buffer */
+#define INBUFSIZE 0x8000
+
+/*
+ * gzip declarations
+ */
+
+#define OF(args)  args
+#define FUNC_STATIC static
+
+typedef unsigned char  uch;
+typedef unsigned short ush;
+typedef unsigned long  ulg;
+
+
+typedef struct segment {
+       unsigned long addr;     /* start address */
+               unsigned long offset;   /* file offset   */
+               unsigned long size;     /* file size     */
+       unsigned long bss_sz;   /* BSS size      */
+       UINT8   flags;  /* indicates whether to load or not */
+} segment_t;
+
+#define CHUNK_FL_VALID         0x1
+#define CHUNK_FL_LOAD          0x2
+
+#define CHUNK_CAN_LOAD(n)      chunks[(n)].flags |= CHUNK_FL_LOAD
+#define CHUNK_NO_LOAD(n)       chunks[(n)].flags &= ~CHUNK_FL_LOAD
+#define CHUNK_IS_LOAD(n)       (chunks[(n)].flags & CHUNK_FL_LOAD)
+
+#define CHUNK_VALIDATE(n)      chunks[(n)].flags |= CHUNK_FL_VALID
+#define CHUNK_INVALIDATE(n)    chunks[(n)].flags = 0
+#define CHUNK_IS_VALID(n)      (chunks[(n)].flags & CHUNK_FL_VALID)
+
+/*
+ * static parameters to gzip helper functions
+ * we cannot use paramters because API was not
+ * designed that way
+ */
+static segment_t *chunks;      /* holds the list of segments */
+static segment_t *cur_chunk;
+static UINTN nchunks;
+static UINTN chunk;                 /* current segment */
+static UINTN input_fd;
+static VOID *kernel_entry, *kernel_base, *kernel_end;
+
+static uch *inbuf;             /* input buffer (compressed data) */
+static uch *window;                    /* output buffer (uncompressed data) */
+static unsigned long file_offset;      /* position in the file */
+
+static unsigned insize = 0;  /* valid bytes in inbuf */
+static unsigned inptr  = 0;   /* index of next byte to be processed in inbuf */
+static unsigned outcnt = 0;  /* bytes in output buffer */
+
+/* gzip flag byte */
+#define ASCII_FLAG   0x01 /* bit 0 set: file probably ASCII text */
+#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
+#define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
+#define ORIG_NAME    0x08 /* bit 3 set: original file name present */
+#define COMMENT      0x10 /* bit 4 set: file comment present */
+#define ENCRYPTED    0x20 /* bit 5 set: file is encrypted */
+#define RESERVED     0xC0 /* bit 6,7:   reserved */
+
+#define get_byte()  (inptr < insize ? inbuf[inptr++] : fill_inbuf())
+
+/* Diagnostic functions */
+#ifdef INFLATE_DEBUG
+#  define Assert(cond,msg) {if(!(cond)) error(msg);}
+int stderr;
+#  define Trace(x) Print(L"line %d:\n", __LINE__);
+#  define Tracev(x) {if (verbose) Print(L"line %d:\n", __LINE__) ;}
+#  define Tracevv(x) {if (verbose>1) Print(L"line %d:\n", __LINE__)  ;}
+#  define Tracec(c,x) {if (verbose && (c))  Print(L"line %d:\n", __LINE__) ;}
+#  define Tracecv(c,x) {if (verbose>1 && (c))  Print(L"line %d:\n", __LINE__) ;}
+#else
+#  define Assert(cond,msg)
+#  define Trace(x)
+#  define Tracev(x)
+#  define Tracevv(x)
+#  define Tracec(c,x)
+#  define Tracecv(c,x)
+#endif
+
+static int  fill_inbuf(void);
+static void flush_window(void);
+static void error(char *m);
+static long bytes_out;
+static void error(char *m);
+static int error_return;
+
+static void *
+gzip_malloc(int size)
+{
+       return (void *)alloc(size, 0);
+}
+
+static void
+gzip_free(void *where)
+{      
+       return free(where);
+}
+
+#include "inflate.c"
+
+/*
+ * Fill the input buffer and return the first byte in it. This is called
+ * only when the buffer is empty and at least one byte is really needed.
+ */
+int
+fill_inbuf(void)
+{
+       INTN expected, nread;
+       EFI_STATUS status;
+
+       expected = nread = INBUFSIZE;
+
+       status = fops_read(input_fd, inbuf, &nread);
+       if (EFI_ERROR(status)) {
+               error("elilo: Read failed");
+       }
+       DBG_PRT((L"%s : read %d bytes of %d bytes\n", LD_NAME, nread, expected));
+
+       insize = nread;
+       inptr = 1;
+
+       return inbuf[0];
+}
+
+/* ===========================================================================
+ * Write the output window window[0..outcnt-1] and update crc and bytes_out.
+ * (Used for the decompressed data only.)
+ */
+
+/*
+ * Run a set of bytes through the crc shift register.  If s is a NULL
+ * pointer, then initialize the crc shift register contents instead.
+ * Return the current crc in either case.
+ *
+ * Input:
+ *     S       pointer to bytes to pump through.
+ *     N       number of bytes in S[].
+ */
+unsigned long
+updcrc(unsigned char *s, unsigned n)
+{
+       register unsigned long c;
+       /* crc is defined in inflate.c */
+
+       if (!s) {
+               c = 0xffffffffL;
+       } else {
+               c = crc;
+               while (n--) {
+                       c = crc_32_tab[((int)c ^ (*s++)) & 0xff] ^ (c >> 8);
+               }
+       }
+       crc = c;
+       return c ^ 0xffffffffUL;       /* (instead of ~c for 64-bit machines) */
+}
+
+
+/*
+ * Clear input and output buffers
+ */
+void
+clear_bufs(void)
+{
+       outcnt = 0;
+       inptr = 0;
+       chunk = 0;
+       cur_chunk = NULL;
+       file_offset = 0;
+}
+
+
+static INTN
+is_valid_header(Elf32_Ehdr *ehdr)
+{
+       UINT16 type, machine;
+
+       type    = ehdr->e_type;
+       machine = ehdr->e_machine;
+       
+       VERB_PRT(3, Print(L"class=%d type=%d data=%d machine=%d\n", 
+               ehdr->e_ident[EI_CLASS],
+               type,
+               ehdr->e_ident[EI_DATA],
+               machine));
+
+       return    ehdr->e_ident[EI_MAG0]  == 0x7f 
+              && ehdr->e_ident[EI_MAG1]  == 'E'
+              && ehdr->e_ident[EI_MAG2]  == 'L'
+              && ehdr->e_ident[EI_MAG3]  == 'F'
+              && ehdr->e_ident[EI_CLASS] == ELFCLASS32 
+              && type                    == ET_EXEC    /* must be executable */
+              && machine                 == EM_386 ? 0 : -1;
+}
+
+/*
+ * will invalidate loadble segments which overlap with others
+ */ 
+void
+check_overlap(int i)
+{
+       int j;
+       unsigned long iend = chunks[i].addr + chunks[i].size;
+
+       for(j=0; j < nchunks; j++) {
+               if (j ==i) continue;
+               if (chunks[i].addr >= chunks[j].addr && iend < (chunks[j].addr + chunks[j].size)) {
+                       DBG_PRT((L"%s : segment %d fully included in segment %d\n", LD_NAME, i, j));
+                       CHUNK_INVALIDATE(i); /* nullyify segment */
+                       break;
+               }
+       }
+}
+
+void
+analyze_chunks(void)
+{
+       INTN i;
+
+       for (i=0; i < nchunks; i++) {
+               if (CHUNK_IS_VALID(i) && !CHUNK_IS_LOAD(i)) 
+                       check_overlap(i);
+       }
+}
+
+
+/*
+ * The decompression code calls this function after decompressing the
+ * first block of the object file.  The first block must contain all
+ * the relevant header information.
+ */
+int
+first_block (const char *buf, long blocksize)
+{
+       Elf32_Ehdr *elf;
+       Elf32_Phdr *phdrs;
+       UINTN total_size, pages;
+       UINTN low_addr, max_addr;
+       UINTN offs = 0;
+       UINT16 phnum;
+       UINTN paddr, memsz;
+       INTN i;
+
+       elf  = (Elf32_Ehdr *)buf;
+       
+       if (is_valid_header(elf) == -1) 
+               return -1;
+
+       offs  = elf->e_phoff;
+       phnum = elf->e_phnum;
+
+       VERB_PRT(3, { 
+               Print(L"Entry point 0x%lx\n", elf->e_entry);
+               Print(L"%d program headers\n", phnum);
+               Print(L"%d segment headers\n", elf->e_shnum);
+       });
+
+       if (offs + phnum * sizeof(*phdrs) > (unsigned) blocksize) {
+               ERR_PRT((L"%s : ELF program headers not in first block (%ld)\n", LD_NAME, offs));
+               return -1;
+       }
+
+       kernel_entry = (VOID *)(elf->e_entry & PADDR_MASK);
+
+       phdrs = (Elf32_Phdr *) (buf + offs);
+       low_addr = ~0;
+       max_addr = 0;
+
+       /*
+        * allocate chunk table
+        * Convention: a segment that does not need loading will
+        * have chunk[].addr = 0.
+        */
+       chunks = (void *)alloc(sizeof(struct segment)*phnum, 0);
+       if (chunks == NULL) {
+               ERR_PRT((L"%s : failed alloc chunks %r\n", LD_NAME));
+               return -1;
+       }
+       nchunks = phnum;
+       /*
+        * find lowest and higest virtual addresses
+        * don't assume FULLY sorted !
+        */
+       for (i = 0; i < phnum; ++i) {
+               /* 
+                * record chunk no matter what because no load may happen
+                * anywhere in archive, not just as the last segment
+                */
+               paddr = (phdrs[i].p_paddr & PADDR_MASK);
+               memsz = phdrs[i].p_memsz,
+
+               chunks[i].addr   = paddr;
+               chunks[i].offset = phdrs[i].p_offset;
+               chunks[i].size   = phdrs[i].p_filesz;
+               chunks[i].bss_sz = phdrs[i].p_memsz - phdrs[i].p_filesz;
+
+               CHUNK_VALIDATE(i);
+
+               if (phdrs[i].p_type != PT_LOAD) {
+                       CHUNK_NO_LOAD(i); /* mark no load chunk */
+                       DBG_PRT((L"%s : skipping segment %ld\n", LD_NAME, i));
+                       continue;
+               }
+
+               CHUNK_CAN_LOAD(i); /* mark no load chunk */
+
+               VERB_PRT(3, 
+               Print(L"\n%s : segment %ld vaddr [0x%lx-0x%lx] offset %ld filesz %ld "
+                       "memsz=%ld bss_sz=%ld\n",
+                       LD_NAME, 1+i, chunks[i].addr, chunks[i].addr+phdrs[i].p_filesz, 
+                       chunks[i].offset, chunks[i].size, memsz, chunks[i].bss_sz));
+               
+               if (paddr < low_addr) 
+                       low_addr = paddr;
+               if (paddr + memsz > max_addr) 
+                       max_addr = paddr + memsz;
+       }
+
+       if (low_addr & (EFI_PAGE_SIZE - 1)) {
+               ERR_PRT((L"%s : low_addr not page aligned 0x%lx\n", LD_NAME, low_addr));
+               goto error;
+       }
+       analyze_chunks();
+
+       DBG_PRT((L"%s : %d program headers entry=0x%lx\nlowest_addr=0x%lx highest_addr=0x%lx\n", 
+                       LD_NAME,
+                       phnum, kernel_entry, low_addr, max_addr));
+
+       total_size = (UINTN)max_addr - (UINTN)low_addr;
+       pages = EFI_SIZE_TO_PAGES(total_size);
+
+       /*
+        * Record end of kernel for initrd
+        */
+       kernel_base = (void *)low_addr;
+       kernel_end  = (void *)(low_addr + (pages << EFI_PAGE_SHIFT));
+
+       /* allocate memory for the kernel */
+       if (alloc_kmem((void *)low_addr, pages) == -1) {
+               ERR_PRT((L"%s : AllocatePages(%d, 0x%lx) for kernel failed\n", 
+                       LD_NAME, pages, low_addr));
+               ERR_PRT((L"%s : Could not load kernel at 0x%lx\n", LD_NAME, low_addr));
+               ERR_PRT((L"%s : Bailing\n", LD_NAME));
+               goto error;
+       }
+       return 0;
+error:
+       if (chunks) 
+               free(chunks);
+       return -1;
+}
+
+/*
+ * Determine which chunk in the Elf file will be coming out of the expand
+ * code next.
+ */
+static void
+nextchunk(void)
+{
+       int i;
+       segment_t *cp;
+
+       cp = NULL;
+       for(i=0; i < nchunks; i++) {
+
+               if (!CHUNK_IS_VALID(i) || !CHUNK_IS_LOAD(i)) continue;
+
+               if (file_offset > chunks[i].offset) continue;
+
+               if (cp == NULL || chunks[i].offset < cp->offset) cp = &chunks[i];
+       }
+       cur_chunk = cp;
+}
+
+
+/*
+ * Write the output window window[0..outcnt-1] holding uncompressed
+ * data and update crc.
+ */
+void
+flush_window(void)
+{
+       static const CHAR8 helicopter[4] = { '|' , '/' , '-' , '\\' };
+       static UINTN heli_count;
+       struct segment *cp;
+       char    *src, *dst;
+       long    cnt;
+
+       if (!outcnt) return;
+
+       DBG_PRT((L"%s : flush_window outnct=%d file_offset=%ld\n", LD_NAME, outcnt, file_offset));
+
+       Print(L"%c\b",helicopter[heli_count++%4]);
+
+       updcrc(window, outcnt);
+
+       /* first time, we extract the headers */
+       if (!bytes_out) {
+               if (first_block(window, outcnt) < 0) 
+                       error("invalid exec header"); 
+               nextchunk();
+       }
+
+       bytes_out += outcnt;
+       src = window;
+tail:
+       /* check if user wants to abort */
+       if (check_abort() == EFI_SUCCESS) goto load_abort;
+
+       cp = cur_chunk;
+       if (cp == NULL || file_offset + outcnt <= cp->offset) {
+               file_offset += outcnt;
+               return;
+       }
+
+       /* Does this window begin before the current chunk? */
+       if (file_offset < cp->offset) {
+               unsigned long skip = cp->offset - file_offset;
+
+               src         += skip;
+               file_offset += skip;
+               outcnt      -= skip;
+       }
+       dst = (char *)cp->addr + (file_offset - cp->offset);
+       cnt = cp->offset + cp->size - file_offset;
+       if (cnt > outcnt) 
+               cnt = outcnt;
+
+       Memcpy(dst, src, cnt);
+
+       file_offset += cnt;
+       outcnt      -= cnt;
+       src         += cnt;
+
+       /* See if we are at the end of this chunk */
+       if (file_offset == cp->offset + cp->size) {
+               if (cp->bss_sz) {
+                       dst = (char *)cp->addr + cp->size;
+                       Memset(dst, 0, cp->bss_sz);
+               }
+               nextchunk();
+               /* handle remaining bytes */
+               if (outcnt) 
+                       goto tail; 
+       }
+       return;
+load_abort:
+       free_kmem();
+       error_return = ELILO_LOAD_ABORTED;
+}
+
+static void
+error(char *x)
+{
+       ERR_PRT((L"%s : %a", LD_NAME, x));
+       /* will eventually exit with error from gunzip() */
+}
+
+INT32
+decompress_kernel(VOID)
+{
+       INT32 ret;
+
+       clear_bufs();
+       makecrc();
+       Print(L"Uncompressing Linux... ");
+       ret = gunzip();
+       if (ret == 0) 
+               Print(L"done\n");
+       return ret == 0 ? 0 : -1;
+}
+
+int
+gunzip_kernel(fops_fd_t fd, kdesc_t *kd)
+{
+       int ret = -1;
+
+       error_return = ELILO_LOAD_ERROR;
+       
+       window = (void *)alloc(WSIZE, 0);
+       if (window == NULL) {
+               ERR_PRT((L"%s : allocate output window failed\n", LD_NAME));
+               return -1;
+       }
+
+       inbuf = (void *)alloc(INBUFSIZE, 0);
+       if (inbuf == NULL) {
+               ERR_PRT((L"%s : allocate input window failedr\n", LD_NAME));
+               goto error;
+       }
+       input_fd   = fd;
+       insize     = 0;
+       bytes_out  = 0;
+
+       ret = decompress_kernel();
+error:
+       if (window) free(window);
+       if (inbuf) free(inbuf);
+
+       if (ret == 0) {
+               kd->kentry = kernel_entry;
+               kd->kend   = kernel_end;
+               kd->kstart = kernel_base;
+               error_return = ELILO_LOAD_SUCCESS;
+       }
+       return error_return;
+}
diff --git a/ia32/gzip_loader.c b/ia32/gzip_loader.c
new file mode 100644 (file)
index 0000000..2e11b84
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ *  Copyright (C) 2001-2002 Hewlett-Packard Co.
+ *     Contributed by Stephane Eranian <eranian@hpl.hp.com>
+ *
+ * This file is part of the ELILO, the EFI Linux boot loader.
+ *
+ *  ELILO 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 2, or (at your option)
+ *  any later version.
+ *
+ *  ELILO 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 ELILO; see the file COPYING.  If not, write to the Free
+ *  Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ *  02111-1307, USA.
+ *
+ * Please check out the elilo.txt for complete documentation on how
+ * to use this program.
+ */
+
+#include <efi.h>
+#include <efilib.h>
+
+#include "elilo.h"
+#include "loader.h"
+#include "gzip.h"
+
+#define LD_NAME L"gzip_ia32"
+
+static INTN
+gzip_probe_format(CHAR16 *kname)
+{
+       UINT8 buf[4];
+       EFI_STATUS status;
+       INTN ret = -1;
+       UINTN size;
+       fops_fd_t fd;
+
+       status = fops_open(kname, &fd);
+       if (EFI_ERROR(status)) return -1;
+
+       size = sizeof(buf);
+       status = fops_read(fd, buf, &size);
+
+       if (EFI_ERROR(status) || size != sizeof(buf)) goto error;
+
+       ret = gzip_probe(buf, sizeof(buf));
+error:
+       fops_close(fd);
+       return ret;
+}
+
+
+static INTN
+gzip_load_kernel(CHAR16 *kname, kdesc_t *kd)
+{
+       EFI_STATUS status;
+       INT32 ret;
+       fops_fd_t fd;
+
+       status = fops_open(kname, &fd);
+       if (EFI_ERROR(status)) return ELILO_LOAD_ERROR;
+
+       ret = gunzip_kernel(fd, kd);
+       
+       fops_close(fd);
+
+       return ret; /* could be success, error, or abort */
+}
+
+loader_ops_t gzip_loader={
+       NULL,
+       LD_NAME,
+       gzip_probe_format,
+       gzip_load_kernel
+};
diff --git a/ia32/plain_loader.c b/ia32/plain_loader.c
new file mode 100644 (file)
index 0000000..ac4c573
--- /dev/null
@@ -0,0 +1,285 @@
+/*
+ *  Copyright (C) 2001-2002 Hewlett-Packard Co.
+ *     Contributed by Stephane Eranian <eranian@hpl.hp.com>
+ *
+ *  Copyright (C) 2001 Silicon Graphics, Inc.
+ *      Contributed by Brent Casavant <bcasavan@sgi.com>
+ *
+ * This file is part of the ELILO, the EFI Linux boot loader.
+ *
+ *  ELILO 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 2, or (at your option)
+ *  any later version.
+ *
+ *  ELILO 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 ELILO; see the file COPYING.  If not, write to the Free
+ *  Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ *  02111-1307, USA.
+ *
+ * Please check out the elilo.txt for complete documentation on how
+ * to use this program.
+ */
+
+#include <efi.h>
+#include <efilib.h>
+
+#include "elilo.h"
+#include "loader.h"
+#include "elf.h"
+#include "private.h"
+
+#define LD_NAME L"plain_elf32"
+
+static INTN
+is_valid_header(Elf32_Ehdr *ehdr)
+{
+       UINT16 type, machine;
+
+       type    = ehdr->e_type;
+       machine = ehdr->e_machine;
+
+       DBG_PRT((L"class=%d type=%d data=%d machine=%d\n", 
+               ehdr->e_ident[EI_CLASS],
+               type,
+               ehdr->e_ident[EI_DATA],
+               machine));
+
+       return    ehdr->e_ident[EI_MAG0]  == 0x7f 
+              && ehdr->e_ident[EI_MAG1]  == 'E'
+              && ehdr->e_ident[EI_MAG2]  == 'L'
+              && ehdr->e_ident[EI_MAG3]  == 'F'
+              && ehdr->e_ident[EI_CLASS] == ELFCLASS32 
+              && type                    == ET_EXEC    /* must be executable */
+              && machine                 == EM_386 ? 0 : -1;
+}
+
+static INTN
+plain_probe(CHAR16 *kname)
+{
+       Elf32_Ehdr ehdr;
+       EFI_STATUS status;
+       INTN ret = -1;
+       fops_fd_t fd;
+       UINTN size = sizeof(ehdr);
+
+       status = fops_open(kname, &fd);
+       if (EFI_ERROR(status)) 
+               return -1;
+
+       status = fops_read(fd, &ehdr, &size);
+       if (EFI_ERROR(status) || size != sizeof(ehdr)) 
+               goto error;
+
+       ret = is_valid_header(&ehdr);
+error:
+       fops_close(fd);
+       return ret;
+}
+
+
+static INTN
+load_elf(fops_fd_t fd, kdesc_t *kd)
+{
+       Elf32_Ehdr ehdr;
+       Elf32_Phdr *phdrs;
+       EFI_STATUS status;
+       INTN ret = ELILO_LOAD_ERROR;
+       UINTN i, total_size = 0;
+       UINTN pages, size, bss_sz, osize;
+       VOID *low_addr = (VOID *)~0;
+       VOID *max_addr = (VOID *)0;
+       UINTN paddr, memsz, filesz;
+       UINT16 phnum;
+
+       Print(L"Loading Linux... ");
+
+       size = sizeof(ehdr);
+
+       status = fops_read(fd, &ehdr, &size);
+       if (EFI_ERROR(status) || size < sizeof(ehdr)) 
+               return ELILO_LOAD_ERROR;
+
+       if (is_valid_header(&ehdr) == -1) {
+               ERR_PRT((L"%s : not a 32-bit ELF image\n", LD_NAME));
+               return ELILO_LOAD_ERROR;
+       }        
+       VERB_PRT(3, {
+               Print(L"ELF Header information: \n");
+               Print(L"\tEntry point 0x%x\n", (ehdr.e_entry & PADDR_MASK));
+               Print(L"\t%d program headers\n", ehdr.e_phnum);
+               Print(L"\t%d segment headers\n", ehdr.e_shnum);
+       });
+
+       phnum = ehdr.e_phnum;
+
+       if (fops_seek(fd, ehdr.e_phoff) < 0) {
+               ERR_PRT((L"%s : seek to %d for phdrs failed", LD_NAME, ehdr.e_phoff));
+               return ELILO_LOAD_ERROR;
+       }
+       size = osize = (phnum * sizeof(Elf32_Phdr));
+
+       DBG_PRT((L"%s : allocate %d bytes for %d pheaders each of size:%d phentsize=%d\n", 
+               LD_NAME, size, phnum, sizeof(Elf32_Phdr), ehdr.e_phentsize));
+
+       phdrs = (Elf32_Phdr *)alloc(size, 0); 
+       if (phdrs == NULL) {
+               ERR_PRT((L"%s : allocate for phdrs failed", LD_NAME));
+               return ELILO_LOAD_ERROR;
+       }
+       status = fops_read(fd, phdrs, &size);
+       if (EFI_ERROR(status) || size != osize) {
+               ERR_PRT((L"%s : phdr load failed", LD_NAME, status));
+               goto out;
+       }
+       /*
+        * First pass to figure out total memory footprint
+        */
+       for (i = 0; i < phnum; i++) {
+
+               paddr = (phdrs[i].p_paddr & PADDR_MASK);
+               memsz = phdrs[i].p_memsz;
+
+               DBG_PRT((L"Phdr %d paddr [0x%x-0x%x] offset 0x%x"
+                       " filesz 0x%x memsz=0x%x bss_sz=0x%x p_type=0x%x\n",
+                       1+i, paddr, paddr+phdrs[i].p_filesz, phdrs[i].p_offset, 
+                       phdrs[i].p_filesz, memsz, 
+                       (memsz - phdrs[i].p_filesz), phdrs[i].p_type));
+       
+               if (phdrs[i].p_type != PT_LOAD)
+                       continue;
+               if (paddr < (UINTN)low_addr) 
+                       low_addr = (VOID *)paddr;
+               if (paddr + memsz > (UINTN)max_addr) 
+                       max_addr = (VOID *)paddr + memsz;
+       }
+
+       if ((UINTN)low_addr & (EFI_PAGE_SIZE - 1)) {
+               ERR_PRT((L"%s : kernel low address 0x%x not page aligned\n", 
+                       LD_NAME, low_addr));
+               goto out;
+       }
+       /* how many bytes are needed to hold the kernel? */
+       total_size = (UINTN)max_addr - (UINTN)low_addr;
+
+       /* round up to get required number of pages */
+       pages = EFI_SIZE_TO_PAGES(total_size);
+
+       /* keep track of location where kernel starts and ends */
+       kd->kstart = low_addr;
+       kd->kend   = (low_addr + (pages << EFI_PAGE_SHIFT));
+       kd->kentry = (VOID *)(ehdr.e_entry & PADDR_MASK);
+       
+       VERB_PRT(3, {
+               Print(L"Lowest PhysAddr: 0x%x\nTotalMemSize:%d bytes (%d pages)\n",
+                       low_addr, total_size, pages);
+               Print(L"Kernel entry @ 0x%x\n", kd->kentry);
+       });
+       
+       /* now allocate memory for the kernel at the exact requested spot */
+       if (alloc_kmem(low_addr, pages) == -1) {
+               ERR_PRT((L"%s : AllocatePages(%d, 0x%lx) for kernel failed\n", 
+                       LD_NAME, pages, low_addr));
+               ERR_PRT((L"%s : Could not alloc %d pages for the kernel at 0x%lx "
+                       " and relocation is not not been implemented!\n", 
+                       LD_NAME, pages, low_addr));
+               goto load_abort;
+       }
+       /* Pure paranoia.  Clear the memory first.  Just in case... */
+       Memset(low_addr, 0, (pages << EFI_PAGE_SHIFT));
+
+       VERB_PRT(1, Print(L"Press any key to interrupt\n"));
+
+       /* 
+        * Walk through the program headers
+        * and actually load data into physical memory
+        */
+
+       for (i = 0; i < phnum; i++) {
+
+               /* Check for pure loadable segment; ignore if not loadable */
+               if (phdrs[i].p_type != PT_LOAD)
+                       continue;
+
+               VERB_PRT(3, Print(L"poffs: 0x%x (phdrs[%d].p_offset)\n", 
+                       phdrs[i].p_offset, i));
+
+               filesz = phdrs[i].p_filesz;
+               low_addr = (VOID *)((UINTN) phdrs[i].p_paddr & PADDR_MASK);
+
+                /* Move to the right position */
+               if (fops_seek(fd, phdrs[i].p_offset) < 0)
+                       goto out_kernel;
+
+                /* How many BSS bytes to clear */
+               bss_sz = phdrs[i].p_memsz - filesz;
+
+               VERB_PRT(4, {
+                       Print(L"\nHeader #%d\n", i);
+                       Print(L"Offset in file 0x%x\n", phdrs[i].p_offset);
+                       Print(L"Physical addr 0x%x\n", low_addr);
+                       Print(L"BSS size 0x%x bytes\n", bss_sz);
+               });
+
+               /*
+                * Read actual segment into memory
+                */
+               ret = fops_read(fd, low_addr, &filesz);
+               if (ret == ELILO_LOAD_ABORTED) goto load_abort;
+               if (ret == ELILO_LOAD_ERROR) goto out;
+
+               /*
+                * Clear bss section
+                */
+               if (bss_sz) 
+                       Memset((VOID *)low_addr+filesz, 0, bss_sz);
+       }
+
+       free(phdrs);
+
+       Print(L"..Done\n");
+       return ELILO_LOAD_SUCCESS;
+
+load_abort:
+       Print(L"..Aborted\n");
+       ret = ELILO_LOAD_ABORTED;
+out_kernel:
+       /* free kernel memory */
+       free_kmem();
+out:
+       free(phdrs);
+       return ret;
+}
+
+static INTN
+plain_load_kernel(CHAR16 *kname, kdesc_t *kd)
+{      
+       INTN ret;
+       fops_fd_t fd;
+       EFI_STATUS status;
+
+       /*
+        * Moving the open here simplifies the load_elf() error handling
+        */
+       status = fops_open(kname, &fd);
+       if (EFI_ERROR(status)) return ELILO_LOAD_ERROR;
+
+       Print(L"Loading %s...", kname);
+
+       ret = load_elf(fd, kd);
+       
+       fops_close(fd);
+       return ret;
+}
+
+loader_ops_t plain_loader={
+       NULL,
+       LD_NAME,
+       plain_probe,
+       plain_load_kernel
+};
index d6f33247158c7b3c2c305fb0695d64a58e55bfb1..0cec75ad974b030af800b6f6d33c98d5b685e5d6 100644 (file)
@@ -33,6 +33,7 @@
 #define __ELILO_SYSDEPS_IA32_H__
 
 #define ELILO_ARCH     "IA-32" /* ASCII string */
+#define PADDR_MASK     0xfffffff
 
 /* for now use library versions */
 #define Memset(a,v,n)  SetMem((a),(n),(v))
  * A new bit, LDRFLAG_BOOT_PARAM_RELOC, in the loader_flags
  * field is also defined in this file.
  */
-typedef struct efi_ia32_boot_params {
-       UINT32 size;
-       UINT32 command_line;
-       UINT32 efi_sys_tbl;
-       UINT32 efi_mem_map;
-       UINT32 efi_mem_map_size;
-       UINT32 efi_mem_desc_size;
-       UINT32 efi_mem_desc_version;
-       UINT32 initrd_start;
-       UINT32 initrd_size;
-       UINT32 loader_start; 
-       UINT32 loader_size;
-       UINT32 kernel_start;
-       UINT32 kernel_size;
-       UINT16 num_cols;        
-       UINT16 num_rows;
-       UINT16 orig_x;
-       UINT16 orig_y;  
-} efi_ia32_boot_params_t;
-
-extern efi_ia32_boot_params_t efi_ia32_bp;
+
 #pragma pack(1)
 typedef union ia32_boot_params {
        UINT8 raw[0x2000];
@@ -275,7 +255,9 @@ typedef union ia32_boot_params {
 /* 0x224 */    UINT16 heap_end_ptr;            /* LDR */
 
 /* %%TBD */
-/* 0x226 */    UINT32 base_mem_size;           /* LDR */
+/* 0x226 */    UINT16 unused_7;                /* LDR */
+
+/* 0x228 */    UINT32 cmdline_addr;            /* LDR */
        } s;
 } boot_params_t;
 #pragma pack()
@@ -354,7 +336,6 @@ start_kernel(VOID *kentry, boot_params_t *bp)
        /*
         * Disable interrupts.
         */
-
        asm volatile ( "cli" : : );
 
        /*
@@ -362,11 +343,9 @@ start_kernel(VOID *kentry, boot_params_t *bp)
         */
 
        if (bp->s.initrd_start) {
-               /* %%TBD */
                MEMCPY(15 * 1024 * 1024, bp->s.initrd_start, bp->s.initrd_size);
                bp->s.initrd_start = 15 * 1024 * 1024;
        }
-
        /*
         * Copy boot sector, setup data and command line
         * to final resting place.  We need to copy
@@ -375,20 +354,6 @@ start_kernel(VOID *kentry, boot_params_t *bp)
 
        MEMCPY(high_base_mem, bp, 0x4000);
 
-       /* 
-        * initialize efi ia32 boot params and place them at 1kb up from
-        * the start of the boot command line param.  This results in the 
-        * efi ia32 boot params to be copied to 0x00104c00.  See bootparams.c
-        * for details on how this is arranged.  EFI enabled 
-        * kernels will look for the efi boot params here to know if the
-        * kernel is booting on an EFI platform or legacy BIOS based platfrom
-        */
-
-       efi_ia32_bp.initrd_start = bp->s.initrd_start;
-       efi_ia32_bp.initrd_size = bp->s.initrd_size;
-
-       MEMCPY(high_base_mem + 0x4000 - 0x0400, &efi_ia32_bp, sizeof(efi_ia32_bp));
        /*
         * Initialize Linux GDT.
         */
@@ -429,7 +394,6 @@ start_kernel(VOID *kentry, boot_params_t *bp)
         * Jump to kernel entry point.
         */
 
-
        asm volatile ( "jmp *%%ecx" : : );
 }
 
index 2e8b8e44a485018c6fe1eb4ab9a61132dde83907..1dbbc587d6ae5e844f15435c68c91232f4e1fd41 100644 (file)
  */
 
 /*
- * this file contains all the IA-32 specific code expected by generic loader
+ * This file contains all the IA-32 specific code expected by generic loader
  */
 #include <efi.h>
 #include <efilib.h>
 
 #include "elilo.h"
 #include "loader.h"
-
 #include "rmswitch.h"
 
-/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
-/* extern loader_ops_t plain_loader, gzip_loader; */
-
-efi_ia32_boot_params_t efi_ia32_bp;
-
+extern loader_ops_t bzimage_loader, plain_loader, gzip_loader; 
 
 /*
  * Descriptor table base addresses & limits for Linux startup.
  */
 
 dt_addr_t gdt_addr = { 0x800, 0x94000 };
-dt_addr_t idt_addr = { 0, 0 };
+dt_addr_t idt_addr = { 0, 0 }; 
 
 /*
  * Initial GDT layout for Linux startup.
@@ -77,7 +70,6 @@ UINT16 init_gdt[] = {
 
 UINTN sizeof_init_gdt = sizeof init_gdt;
 
-
 /*
  * Highest available base memory address.
  *
@@ -98,266 +90,33 @@ UINTN high_base_mem = 0x90000;
  *
  * This is computed by taking the highest available extended memory
  * address and rounding down to the nearest EFI_PAGE_SIZE (usually
- * 4 kB) boundary.  The ia32 Linux kernel can only support up to
- * 2 GB (AFAIK).
+ * 4 kB) boundary.  
+ * This is only used for backward compatibility.
  */
 
 UINTN high_ext_mem = 32 * 1024 * 1024;
 
-/*
- * Starting location and size of runtime memory blocks.
- */
-
-boot_params_t *param_start = NULL;
-UINTN param_size = 0;
-
+/* This starting address will hold true for all of the loader types for now */
 VOID *kernel_start = (VOID *)0x100000; /* 1M */
-UINTN kernel_size = 0x200000;          /* 2M (largest x86 kernel image) */
 
 VOID *initrd_start = NULL;
 UINTN initrd_size = 0;
 
-/*
- * Boot parameters can be relocated if TRUE.
- * Boot parameters must be placed at 0x90000 if FALSE.
- *
- * This will be set to TRUE if bit 6 (0x40) is set in the loader_flags
- * field in a compressed x86 boot format kernel.  This will also be set
- * to TRUE if the kernel is an uncompressed ELF32 image.
- *
- * To remote boot w/ the universal network driver and a 16-bit UNDI
- * this must be set to TRUE.
- */
-
-BOOLEAN can_reloc_boot_params = FALSE;
-
-/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-static INTN
-probe_bzImage_boot(CHAR16 *kname)
-{
-       EFI_STATUS efi_status;
-       UINTN size;
-       fops_fd_t fd;
-       UINT8 bootsect[512];
-
-       DBG_PRT((L"probe_bzImage_boot()\n"));
-
-       if (!kname) {
-               ERR_PRT((L"kname == %xh", kname));
-               free_kmem();
-               return -1;
-       }
-
-       /*
-        * Open kernel image.
-        */
-
-       DBG_PRT((L"opening %s...\n", kname));
-
-       efi_status = fops_open(kname, &fd);
-
-       if (EFI_ERROR(efi_status)) {
-               ERR_PRT((L"Could not open %s.", kname));
-               free_kmem();
-               return -1;
-       }
-
-       /*
-        * Read boot sector.
-        */
-
-       DBG_PRT((L"\nreading boot sector...\n"));
-
-       size = sizeof bootsect;
-       efi_status = fops_read(fd, bootsect, &size);
-
-       if (EFI_ERROR(efi_status) || size != sizeof bootsect) {
-               ERR_PRT((L"Could not read boot sector from %s.", kname));
-               fops_close(fd);
-               free_kmem();
-               return -1;
-       }
-
-       /*
-        * Verify boot sector signature.
-        */
-
-       if (bootsect[0x1FE] != 0x55 || bootsect[0x1FF] != 0xAA) {
-               ERR_PRT((L"%s is not a bzImage kernel image.\n", kname));
-               fops_close(fd);
-               free_kmem();
-               return -1;
-       }
-
-       /*
-        * Check for out of range setup data size.
-        * Will almost always be 7, but we will accept 1 to 64.
-        */
-
-       DBG_PRT((L"bootsect[1F1h] == %d setup sectors\n", bootsect[0x1F1]));
-
-       if (bootsect[0x1F1] < 1 || bootsect[0x1F1] > 64) {
-               ERR_PRT((L"%s is not a valid bzImage kernel image.",
-                       kname));
-
-               fops_close(fd);
-               free_kmem();
-               return -1;
-       }
-
-       /*
-        * Allocate and read setup data.
-        */
-
-       DBG_PRT((L"reading setup data...\n"));
-
-       param_size = (bootsect[0x1F1] + 1) * 512;
-       //param_start = alloc(param_size, EfiBootServicesData);
-       param_start = alloc(param_size, EfiLoaderData);
-
-       DBG_PRT((L"param_size=%d param_start=%x", param_size, param_start));
-
-       if (!param_start) {
-               ERR_PRT((L"Could not allocate %d bytes of setup data.",
-                       param_size));
-
-               fops_close(fd);
-               free_kmem();
-               return -1;
-       }
-
-       CopyMem(param_start, bootsect, sizeof bootsect);
-
-       size = param_size - 512;
-       efi_status = fops_read(fd, ((UINT8 *)param_start) + 512, &size);
-
-       if (EFI_ERROR(efi_status) || size != param_size - 512) {
-               ERR_PRT((L"Could not read %d bytes of setup data.",
-                       param_size - 512));
-
-               free(param_start);
-               param_start = NULL;
-               param_size = 0;
-               fops_close(fd);
-               free_kmem();
-               return -1;
-       }
-
-       /*
-        * Check for setup data signature.
-        */
-
-       { UINT8 *c = ((UINT8 *)param_start)+514;
-       DBG_PRT((L"param_start(c=%x): %c-%c-%c-%c", c, (CHAR16)c[0],(CHAR16) c[1], (CHAR16)c[2], (CHAR16)c[3]));
-       }
-       if (CompareMem(((UINT8 *)param_start) + 514, "HdrS", 4)) {
-               ERR_PRT((L"%s does not have a setup signature.",
-                       kname));
-
-               free(param_start);
-               param_start = NULL;
-               param_size = 0;
-               fops_close(fd);
-               free_kmem();
-               return -1;
-       }
-
-       /*
-        * Allocate memory for kernel.
-        */
-
-       if (alloc_kmem(kernel_start, EFI_SIZE_TO_PAGES(kernel_size))) {
-               ERR_PRT((L"Could not allocate kernel memory."));
-               return -1;
-       } else {
-               VERB_PRT(3, Print(L"kernel_start: 0x%x  kernel_size: %d\n", kernel_start, kernel_size));
-       }
-
-       /*
-        * Now read the rest of the kernel image into memory.
-        */
-
-       DBG_PRT((L"reading kernel image...\n"));
-
-       size = kernel_size;
-
-       efi_status = fops_read(fd, kernel_start, &size);
-
-       if (EFI_ERROR(efi_status) || size < 0x10000) {
-               ERR_PRT((L"Error reading kernel image %s.", kname));
-               free(param_start);
-               param_start = NULL;
-               param_size = 0;
-               fops_close(fd);
-               free_kmem();
-               return -1;
-       }
-
-       DBG_PRT((L"kernel image read:  %d bytes, %d Kbytes\n", size, size / 1024));
-
-       /*
-        * Boot sector, setup data and kernel image loaded.
-        */
-
-       fops_close(fd);
-       return 0;
-}
-
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-static INTN
-load_bzImage_boot(CHAR16 *kname, kdesc_t *kd)
-{
-       DBG_PRT((L"load_bzImage_boot()\n"));
-
-       if (!kname || !kd) {
-               ERR_PRT((L"kname=0x%x  kd=0x%x", kname, kd));
-
-               free(param_start);
-               param_start = NULL;
-               param_size = 0;
-               free_kmem();
-               return -1;
-       }
-
-       kd->kstart = kd->kentry = kernel_start;
-       kd->kend = ((UINT8 *)kd->kstart) + kernel_size;
-
-       DBG_PRT((L"kstart=0x%x  kentry=0x%x  kend=0x%x\n", kd->kstart, kd->kentry, kd->kend));
-
-       return 0;
-}
-
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-static loader_ops_t loader_bzImage_boot = {
-       NULL,
-       L"loader_bzImage_boot",
-       &probe_bzImage_boot,
-       &load_bzImage_boot
-};
-
-/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 INTN
 sysdeps_init(EFI_HANDLE dev)
 {
-
        DBG_PRT((L"sysdeps_init()\n"));
 
        /*
         * Register our loader(s)...
         */
 
-       loader_register(&loader_bzImage_boot);
-       /* loader_register(&plain_loader); */   
-       /* loader_register(&gzip_loader); */
-
-
+       loader_register(&bzimage_loader);
+       loader_register(&plain_loader);         
+       loader_register(&gzip_loader); 
        return 0;
 }
 
-/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 /*
  * initrd_get_addr()
  *     Compute a starting address for the initial RAMdisk image.
@@ -381,13 +140,12 @@ sysdeps_initrd_get_addr(kdesc_t *kd, memdesc_t *imem)
 
        imem->start_addr = kd->kend;
 
-       VERB_PRT(3, Print(L"initrd start_addr=0x%x pgcnt=%d\n", imem->start_addr, imem->pgcnt));
+       VERB_PRT(3, Print(L"initrd start_addr=0x%x pgcnt=%d\n", 
+               imem->start_addr, imem->pgcnt));
 
        return 0;
 }
 
-/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 VOID
 sysdeps_free_boot_params(boot_params_t *bp)
 {
@@ -398,8 +156,6 @@ sysdeps_free_boot_params(boot_params_t *bp)
        free_memmap(&md);
 }
 
-/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 /*
  * IA-32 specific boot parameters initialization routine
  */
@@ -408,6 +164,7 @@ sysdeps_create_boot_params(
        boot_params_t *bp,
        CHAR8 *cmdline,
        memdesc_t *initrd,
+       memdesc_t *vmcode, /* no use for ia32 now*/
        UINTN *cookie)
 {
        mmap_desc_t mdesc;
@@ -423,9 +180,11 @@ sysdeps_create_boot_params(
                ERR_PRT((L"bp=0x%x  cmdline=0x%x  initrd=0x%x cookie=0x%x",
                        bp, cmdline, initrd, cookie));
 
-               free(param_start);
-               param_start = NULL;
-               param_size = 0;
+               if (param_start != NULL) {
+                       free(param_start);
+                       param_start = NULL;
+                       param_size = 0;
+               }
                free_kmem();
                return -1;
        }
@@ -436,29 +195,27 @@ sysdeps_create_boot_params(
         * the first two sectors (1K).  The rest of the storage
         * can be used by the command line.
         */
-
-       CopyMem(bp, param_start, 0x2000);
-
-       free(param_start);
-       param_start = NULL;
-       param_size = 0;
-
+       if (param_start != NULL) {
+               CopyMem(bp, param_start, 0x2000);
+               free(param_start);
+               param_start = NULL;
+               param_size = 0;
+       }
        /*
         * Save off our header revision information.
         */
-
        hdr_version = (bp->s.hdr_major << 8) | bp->s.hdr_minor;
 
        /*
         * Clear out unused memory in boot sector image.
         */
-
        bp->s.unused_1 = 0;
        bp->s.unused_2 = 0;
        ZeroMem(bp->s.unused_3, sizeof bp->s.unused_3);
        ZeroMem(bp->s.unused_4, sizeof bp->s.unused_4);
        ZeroMem(bp->s.unused_5, sizeof bp->s.unused_5);
        bp->s.unused_6 = 0;
+       bp->s.unused_7 = 0;
 
        /*
         * Tell kernel this was loaded by an advanced loader type.
@@ -475,6 +232,12 @@ sysdeps_create_boot_params(
        bp->s.cmdline_magik = CMDLINE_MAGIK;
        bp->s.cmdline_offset = (UINT8 *)cmdline - (UINT8 *)bp;
 
+       /* 
+        * Clear out the cmdline_addr field so the kernel can find 
+        * the cmdline.
+        */
+       bp->s.cmdline_addr = 0x0;
+
        /*
         * Setup hard drive parameters.
         * %%TBD - It should be okay to zero fill the hard drive
@@ -484,28 +247,16 @@ sysdeps_create_boot_params(
        ZeroMem(bp->s.hd0_info, sizeof bp->s.hd0_info);
        ZeroMem(bp->s.hd1_info, sizeof bp->s.hd1_info);
 
-#if 0
-       CopyMem(bp->s.hd0_info, *((VOID **)(0x41 * 4)),
-               sizeof bp->s.hd0_info);
-
-       CopyMem(bp->s.hd1_info, *((VOID **)(0x46 * 4)),
-               sizeof bp->s.hd1_info);
-#endif
-
        /*
         * Memory info.
         */
 
        bp->s.alt_mem_k = high_ext_mem / 1024;
 
-       if (bp->s.alt_mem_k <= 65535) {
+       if (bp->s.alt_mem_k <= 65535) 
                bp->s.ext_mem_k = (UINT16)bp->s.alt_mem_k;
-       } else {
+       else 
                bp->s.ext_mem_k = 65535;
-       }
-
-       if (hdr_version < 0x0202)
-               bp->s.base_mem_size = high_base_mem;
 
        /*
         * Initial RAMdisk and root device stuff.
@@ -520,29 +271,22 @@ sysdeps_create_boot_params(
        if (initrd->start_addr && initrd->pgcnt) {
                /* %%TBD - This will probably have to be changed. */
                bp->s.initrd_start = (UINT32)initrd->start_addr;
-               bp->s.initrd_size = (UINT32)(initrd->pgcnt * EFI_PAGE_SIZE);
+               bp->s.initrd_size = (UINT32)(initrd->size);
 
                /*
                 * This is the RAMdisk root device for RedHat 2.2.x
                 * kernels (major 0x01, minor 0x00).
-                * %%TBD - Will this work for other distributions and
-                * 2.3.x and 2.4.x kernels?  I do not know, yet.
                 */
 
                bp->s.orig_root_dev = 0x0100;
        } else {
                bp->s.initrd_start = 0;
                bp->s.initrd_size = 0;
-
-               /* Do not change the root device if there is no RAMdisk. */
-               /* bp->s.orig_root_dev = 0; */
        }
 
        /*
         * APM BIOS info.
         */
-
-/* %%TBD - How to do Int 15h calls to get this info? */
        bp->s.apm_bios_ver = NO_APM_BIOS;
        bp->s.bios_code_seg = 0;
        bp->s.bios_entry_point = 0;
@@ -555,29 +299,22 @@ sysdeps_create_boot_params(
        /*
         * MCA BIOS info (misnomer).
         */
-
-/* %%TBD - How to do Int 15h call to get this info? */
        bp->s.mca_info_len = 0;
        ZeroMem(bp->s.mca_info_buf, sizeof bp->s.mca_info_buf);
 
        /*
-        * Pointing device presence.
+        * Pointing device presence.  The kernel will detect this.
         */
-
-/* %%TBD - How to do Int 11h call to get this info? */
        bp->s.aux_dev_info = NO_MOUSE;
 
        /*
-        * EFI loader signature and address of EFI system table.
+        * EFI loader signature 
         */
-
        CopyMem(bp->s.efi_loader_sig, EFI_LOADER_SIG, 4);
-       bp->s.efi_sys_tbl = 0; /* %%TBD */
 
        /*
         * Kernel entry point.
         */
-
        bp->s.kernel_start = (UINT32)kernel_start;
 
        /*
@@ -587,6 +324,7 @@ sysdeps_create_boot_params(
         *   arch/i386/boot/bootsect.S
         *   arch/i386/boot/setup.S
         *   arch/i386/kernel/setup.c
+        *   include/asm-i386/setup.h (2.5/2.6)
         */
 
 #define CHECK_OFFSET(n, o, f) \
@@ -610,7 +348,6 @@ sysdeps_create_boot_params(
                ; \
        } \
 }
-
        {
                UINTN test = 0;
 
@@ -688,7 +425,7 @@ sysdeps_create_boot_params(
                CHECK_OFFSET(initrd_size, 0x21C, L"%xh");
                CHECK_OFFSET(bootsect_helper, 0x220, L"%xh");
                CHECK_OFFSET(heap_end_ptr, 0x224, L"%xh");
-               CHECK_OFFSET(base_mem_size, 0x226, L"%xh");
+               CHECK_OFFSET(cmdline_addr, 0x228, L"%xh");
 
                if (test) {
                        ERR_PRT((L"Boot sector and/or setup parameter alignment error."));
@@ -711,7 +448,6 @@ sysdeps_create_boot_params(
 
        if (EFI_ERROR(efi_status)) {
                ERR_PRT((L"QueryMode failed.  Fake it."));
-
                mode = 3;
                rows = 25;
                cols = 80;
@@ -730,12 +466,10 @@ sysdeps_create_boot_params(
        bp->s.orig_video_cols = (UINT8)cols;
        bp->s.orig_video_rows = (UINT8)rows;
 
-/* %%TBD - How to do Int 10h calls to get video info? */
        bp->s.orig_ega_bx = 0;
        bp->s.is_vga = 0;
-       bp->s.orig_video_points = 0;
+       bp->s.orig_video_points = 16; 
 
-/* %%TBD - How to do Int 10h calls to get frame buffer info? */
        bp->s.lfb_width = 0;
        bp->s.lfb_height = 0;
        bp->s.lfb_depth = 0;
@@ -763,7 +497,6 @@ sysdeps_create_boot_params(
                free_kmem();
                return -1;
        }
-
        *cookie = mdesc.cookie;
        bp->s.efi_mem_map = (UINTN)mdesc.md;
        bp->s.efi_mem_map_size = mdesc.map_size;
@@ -771,28 +504,5 @@ sysdeps_create_boot_params(
        bp->s.efi_mem_desc_ver = mdesc.desc_version;
        bp->s.efi_sys_tbl = (UINTN)systab;
        
-       /*
-        * my_ia32_boot_params and get ready to slap them into 0x00104c00
-        */
-
-       efi_ia32_bp.size= sizeof(efi_ia32_bp);
-       efi_ia32_bp.command_line = (UINT32) cmdline;
-       efi_ia32_bp.efi_sys_tbl = bp->s.efi_sys_tbl;
-       efi_ia32_bp.efi_mem_map = bp->s.efi_mem_map;
-       efi_ia32_bp.efi_mem_map_size = bp->s.efi_mem_map_size;
-       efi_ia32_bp.efi_mem_desc_size = bp->s.efi_mem_desc_size;
-       efi_ia32_bp.efi_mem_desc_version = bp->s.efi_mem_desc_ver;
-       efi_ia32_bp.initrd_start = (UINTN)initrd->start_addr;
-       efi_ia32_bp.initrd_size = initrd->pgcnt * EFI_PAGE_SIZE;
-       efi_ia32_bp.loader_start = 0;
-       efi_ia32_bp.loader_size = 0;
-       efi_ia32_bp.kernel_start = bp->s.kernel_start;
-       efi_ia32_bp.kernel_size = kernel_size;
-       efi_ia32_bp.num_cols = cols;
-       efi_ia32_bp.num_rows = rows;
-       efi_ia32_bp.orig_x = col;
-       efi_ia32_bp.orig_y = row;
-
-
        return 0;
 }
index bb5a06592716470d4df3f514c56d8770ab0747c9..01e28c85fe886e8ceca15527230d30135d74a87c 100644 (file)
@@ -37,6 +37,8 @@
 #include "private.h"
 #include "setjmp.h"
 
+#define LD_NAME L"gzip_ia64"
+
 #define memzero(s, n)  Memset((VOID *)(s), 0, (n))
 #define memcpy(a,b,n)  Memcpy((VOID *)(a),(b),(n))
 
@@ -68,6 +70,7 @@ typedef struct segment {
 
 #define CHUNK_FL_VALID         0x1
 #define CHUNK_FL_LOAD          0x2
+#define CHUNK_FL_X             0x4
 
 #define CHUNK_CAN_LOAD(n)      chunks[(n)].flags |= CHUNK_FL_LOAD
 #define CHUNK_NO_LOAD(n)       chunks[(n)].flags &= ~CHUNK_FL_LOAD
@@ -391,6 +394,9 @@ first_block (const char *buf, long blocksize)
                        continue;
                }
 
+               if (bswap32(phdrs[i].p_flags) & PF_X)
+                       chunks[i].flags |= CHUNK_FL_X;
+
                CHUNK_CAN_LOAD(i); /* mark no load chunk */
 
                VERB_PRT(3, 
@@ -433,7 +439,7 @@ first_block (const char *buf, long blocksize)
        if (alloc_kmem((void *)low_addr, pages) == -1) {
                VOID *new_addr;
 
-               ERR_PRT((L"%s : AllocatePages(%d, 0x%lx) for kernel failed\n", LD_NAME, pages, low_addr));
+               VERB_PRT(1, (L"%s : AllocatePages(%d, 0x%lx) for kernel failed\n", LD_NAME, pages, low_addr));
 
                if (ia64_can_relocate() == 0) {
                        ERR_PRT((L"relocation is disabled, cannot load kernel"));
@@ -458,7 +464,7 @@ first_block (const char *buf, long blocksize)
                /* unsigned arithmetic */
                 load_offset = (UINTN) (new_addr - ROUNDDOWN((UINTN) low_addr,256*MB));
 
-               ERR_PRT((L"low_addr=0x%lx new_addr=0x%lx offset=0x%lx", low_addr, new_addr, load_offset));
+               VERB_PRT(1, (L"low_addr=0x%lx new_addr=0x%lx offset=0x%lx", low_addr, new_addr, load_offset));
 
                /*
                 * correct various addresses for non-zero load_offset
@@ -566,6 +572,8 @@ tail:
        if (cnt > outcnt) cnt = outcnt;
 
        Memcpy(dst, src, cnt);
+       if (cp->flags & CHUNK_FL_X)
+               flush_dcache (dst, cnt);
 
        file_offset += cnt;
        outcnt      -= cnt;
diff --git a/ia64/gzip.h b/ia64/gzip.h
deleted file mode 100644 (file)
index 69749df..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- *  Copyright (C) 2001-2003 Hewlett-Packard Co.
- *     Contributed by Stephane Eranian <eranian@hpl.hp.com>
- *
- * This file is part of the ELILO, the EFI Linux boot loader.
- *
- *  ELILO 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 2, or (at your option)
- *  any later version.
- *
- *  ELILO 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 ELILO; see the file COPYING.  If not, write to the Free
- *  Software Foundation, 59 Temple Place - Suite 330, Boston, MA
- *  02111-1307, USA.
- *
- * Please check out the elilo.txt for complete documentation on how
- * to use this program.
- */
-
-#ifndef __GZIP_H__
-#define __GZIP_H__
-
-
-int gzip_probe(unsigned char *, unsigned long);
-int gunzip_kernel(fops_fd_t, kdesc_t *);
-
-#define LD_NAME                L"gzip_ia64"
-
-#endif /* __GZIP_H__ */
index 4e06db4bbb9546e234c5b1e99787263b4798b46b..a84851f5b91bc6c2bd47a01789609e70372a5038 100644 (file)
@@ -30,6 +30,8 @@
 #include "loader.h"
 #include "gzip.h"
 
+#define LD_NAME L"gzip_ia64"
+
 static INTN
 gzip_probe_format(CHAR16 *kname)
 {
diff --git a/ia64/inflate.c b/ia64/inflate.c
deleted file mode 100644 (file)
index 8273c98..0000000
+++ /dev/null
@@ -1,1204 +0,0 @@
-#define DEBG(x)
-#define DEBG1(x)
-/* inflate.c -- Not copyrighted 1992 by Mark Adler
-   version c10p1, 10 January 1993 */
-
-/* 
- * Adapted for booting Linux by Hannu Savolainen 1993
- * based on gzip-1.0.3 
- *
- * Nicolas Pitre <nico@cam.org>, 1999/04/14 :
- *   Little mods for all variable to reside either into rodata or bss segments
- *   by marking constant variables with 'const' and initializing all the others
- *   at run-time only.  This allows for the kernel uncompressor to run
- *   directly from Flash or ROM memory on embeded systems.
- */
-
-/*
-   Inflate deflated (PKZIP's method 8 compressed) data.  The compression
-   method searches for as much of the current string of bytes (up to a
-   length of 258) in the previous 32 K bytes.  If it doesn't find any
-   matches (of at least length 3), it codes the next byte.  Otherwise, it
-   codes the length of the matched string and its distance backwards from
-   the current position.  There is a single Huffman code that codes both
-   single bytes (called "literals") and match lengths.  A second Huffman
-   code codes the distance information, which follows a length code.  Each
-   length or distance code actually represents a base value and a number
-   of "extra" (sometimes zero) bits to get to add to the base value.  At
-   the end of each deflated block is a special end-of-block (EOB) literal/
-   length code.  The decoding process is basically: get a literal/length
-   code; if EOB then done; if a literal, emit the decoded byte; if a
-   length then get the distance and emit the referred-to bytes from the
-   sliding window of previously emitted data.
-
-   There are (currently) three kinds of inflate blocks: stored, fixed, and
-   dynamic.  The compressor deals with some chunk of data at a time, and
-   decides which method to use on a chunk-by-chunk basis.  A chunk might
-   typically be 32 K or 64 K.  If the chunk is incompressible, then the
-   "stored" method is used.  In this case, the bytes are simply stored as
-   is, eight bits per byte, with none of the above coding.  The bytes are
-   preceded by a count, since there is no longer an EOB code.
-
-   If the data is compressible, then either the fixed or dynamic methods
-   are used.  In the dynamic method, the compressed data is preceded by
-   an encoding of the literal/length and distance Huffman codes that are
-   to be used to decode this block.  The representation is itself Huffman
-   coded, and so is preceded by a description of that code.  These code
-   descriptions take up a little space, and so for small blocks, there is
-   a predefined set of codes, called the fixed codes.  The fixed method is
-   used if the block codes up smaller that way (usually for quite small
-   chunks), otherwise the dynamic method is used.  In the latter case, the
-   codes are customized to the probabilities in the current block, and so
-   can code it much better than the pre-determined fixed codes.
-   The Huffman codes themselves are decoded using a multi-level table
-   lookup, in order to maximize the speed of decoding plus the speed of
-   building the decoding tables.  See the comments below that precede the
-   lbits and dbits tuning parameters.
- */
-
-
-/*
-   Notes beyond the 1.93a appnote.txt:
-
-   1. Distance pointers never point before the beginning of the output
-      stream.
-   2. Distance pointers can point back across blocks, up to 32k away.
-   3. There is an implied maximum of 7 bits for the bit length table and
-      15 bits for the actual data.
-   4. If only one code exists, then it is encoded using one bit.  (Zero
-      would be more efficient, but perhaps a little confusing.)  If two
-      codes exist, they are coded using one bit each (0 and 1).
-   5. There is no way of sending zero distance codes--a dummy must be
-      sent if there are none.  (History: a pre 2.0 version of PKZIP would
-      store blocks with no distance codes, but this was discovered to be
-      too harsh a criterion.)  Valid only for 1.93a.  2.04c does allow
-      zero distance codes, which is sent as one code of zero bits in
-      length.
-   6. There are up to 286 literal/length codes.  Code 256 represents the
-      end-of-block.  Note however that the static length tree defines
-      288 codes just to fill out the Huffman codes.  Codes 286 and 287
-      cannot be used though, since there is no length base or extra bits
-      defined for them.  Similarly, there are up to 30 distance codes.
-      However, static trees define 32 codes (all 5 bits) to fill out the
-      Huffman codes, but the last two had better not show up in the data.
-   7. Unzip can check dynamic Huffman blocks for complete code sets.
-      The exception is that a single code would not be complete (see #4).
-   8. The five bits following the block type is really the number of
-      literal codes sent minus 257.
-   9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits
-      (1+6+6).  Therefore, to output three times the length, you output
-      three codes (1+1+1), whereas to output four times the same length,
-      you only need two codes (1+3).  Hmm.
-  10. In the tree reconstruction algorithm, Code = Code + Increment
-      only if BitLength(i) is not zero.  (Pretty obvious.)
-  11. Correction: 4 Bits: # of Bit Length codes - 4     (4 - 19)
-  12. Note: length code 284 can represent 227-258, but length code 285
-      really is 258.  The last length deserves its own, short code
-      since it gets used a lot in very redundant files.  The length
-      258 is special since 258 - 3 (the min match length) is 255.
-  13. The literal/length and distance code bit lengths are read as a
-      single stream of lengths.  It is possible (and advantageous) for
-      a repeat code (16, 17, or 18) to go across the boundary between
-      the two sets of lengths.
- */
-
-#ifdef RCSID
-static char rcsid[] = "#Id: inflate.c,v 0.14 1993/06/10 13:27:04 jloup Exp #";
-#endif
-
-#ifndef FUNC_STATIC
-
-#if defined(STDC_HEADERS) || defined(HAVE_STDLIB_H)
-#  include <sys/types.h>
-#  include <stdlib.h>
-#endif
-
-#include "gzip.h"
-#define FUNC_STATIC
-#endif /* !FUNC_STATIC */
-       
-#define slide window
-
-/* Huffman code lookup table entry--this entry is four bytes for machines
-   that have 16-bit pointers (e.g. PC's in the small or medium model).
-   Valid extra bits are 0..13.  e == 15 is EOB (end of block), e == 16
-   means that v is a literal, 16 < e < 32 means that v is a pointer to
-   the next table, which codes e - 16 bits, and lastly e == 99 indicates
-   an unused code.  If a code with e == 99 is looked up, this implies an
-   error in the data. */
-struct huft {
-  uch e;                /* number of extra bits or operation */
-  uch b;                /* number of bits in this code or subcode */
-  union {
-    ush n;              /* literal, length base, or distance base */
-    struct huft *t;     /* pointer to next level of table */
-  } v;
-};
-
-
-/* Function prototypes */
-FUNC_STATIC int huft_build OF((unsigned *, unsigned, unsigned, 
-               const ush *, const ush *, struct huft **, int *));
-FUNC_STATIC int huft_free OF((struct huft *));
-FUNC_STATIC int inflate_codes OF((struct huft *, struct huft *, int, int));
-FUNC_STATIC int inflate_stored OF((void));
-FUNC_STATIC int inflate_fixed OF((void));
-FUNC_STATIC int inflate_dynamic OF((void));
-FUNC_STATIC int inflate_block OF((int *));
-FUNC_STATIC int inflate OF((void));
-
-
-/* The inflate algorithm uses a sliding 32 K byte window on the uncompressed
-   stream to find repeated byte strings.  This is implemented here as a
-   circular buffer.  The index is updated simply by incrementing and then
-   ANDing with 0x7fff (32K-1). */
-/* It is left to other modules to supply the 32 K area.  It is assumed
-   to be usable as if it were declared "uch slide[32768];" or as just
-   "uch *slide;" and then malloc'ed in the latter case.  The definition
-   must be in unzip.h, included above. */
-/* unsigned wp;             current position in slide */
-#define wp outcnt
-#define flush_output(w) (wp=(w),flush_window())
-
-/* Tables for deflate from PKZIP's appnote.txt. */
-static const unsigned border[] = {    /* Order of the bit length code lengths */
-        16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
-static const ush cplens[] = {         /* Copy lengths for literal codes 257..285 */
-        3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
-        35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
-        /* note: see note #13 above about the 258 in this list. */
-static const ush cplext[] = {         /* Extra bits for literal codes 257..285 */
-        0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
-        3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99}; /* 99==invalid */
-static const ush cpdist[] = {         /* Copy offsets for distance codes 0..29 */
-        1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
-        257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
-        8193, 12289, 16385, 24577};
-static const ush cpdext[] = {         /* Extra bits for distance codes */
-        0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
-        7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
-        12, 12, 13, 13};
-
-
-
-/* Macros for inflate() bit peeking and grabbing.
-   The usage is:
-   
-        NEEDBITS(j)
-        x = b & mask_bits[j];
-        DUMPBITS(j)
-
-   where NEEDBITS makes sure that b has at least j bits in it, and
-   DUMPBITS removes the bits from b.  The macros use the variable k
-   for the number of bits in b.  Normally, b and k are register
-   variables for speed, and are initialized at the beginning of a
-   routine that uses these macros from a global bit buffer and count.
-
-   If we assume that EOB will be the longest code, then we will never
-   ask for bits with NEEDBITS that are beyond the end of the stream.
-   So, NEEDBITS should not read any more bytes than are needed to
-   meet the request.  Then no bytes need to be "returned" to the buffer
-   at the end of the last block.
-
-   However, this assumption is not true for fixed blocks--the EOB code
-   is 7 bits, but the other literal/length codes can be 8 or 9 bits.
-   (The EOB code is shorter than other codes because fixed blocks are
-   generally short.  So, while a block always has an EOB, many other
-   literal/length codes have a significantly lower probability of
-   showing up at all.)  However, by making the first table have a
-   lookup of seven bits, the EOB code will be found in that first
-   lookup, and so will not require that too many bits be pulled from
-   the stream.
- */
-
-FUNC_STATIC ulg bb;                         /* bit buffer */
-FUNC_STATIC unsigned bk;                    /* bits in bit buffer */
-
-FUNC_STATIC const ush mask_bits[] = {
-    0x0000,
-    0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
-    0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
-};
-
-#define NEXTBYTE()  (uch)get_byte()
-#define NEEDBITS(n) {while(k<(n)){b|=((ulg)NEXTBYTE())<<k;k+=8;}}
-#define DUMPBITS(n) {b>>=(n);k-=(n);}
-
-
-/*
-   Huffman code decoding is performed using a multi-level table lookup.
-   The fastest way to decode is to simply build a lookup table whose
-   size is determined by the longest code.  However, the time it takes
-   to build this table can also be a factor if the data being decoded
-   is not very long.  The most common codes are necessarily the
-   shortest codes, so those codes dominate the decoding time, and hence
-   the speed.  The idea is you can have a shorter table that decodes the
-   shorter, more probable codes, and then point to subsidiary tables for
-   the longer codes.  The time it costs to decode the longer codes is
-   then traded against the time it takes to make longer tables.
-
-   This results of this trade are in the variables lbits and dbits
-   below.  lbits is the number of bits the first level table for literal/
-   length codes can decode in one step, and dbits is the same thing for
-   the distance codes.  Subsequent tables are also less than or equal to
-   those sizes.  These values may be adjusted either when all of the
-   codes are shorter than that, in which case the longest code length in
-   bits is used, or when the shortest code is *longer* than the requested
-   table size, in which case the length of the shortest code in bits is
-   used.
-
-   There are two different values for the two tables, since they code a
-   different number of possibilities each.  The literal/length table
-   codes 286 possible values, or in a flat code, a little over eight
-   bits.  The distance table codes 30 possible values, or a little less
-   than five bits, flat.  The optimum values for speed end up being
-   about one bit more than those, so lbits is 8+1 and dbits is 5+1.
-   The optimum values may differ though from machine to machine, and
-   possibly even between compilers.  Your mileage may vary.
- */
-
-
-FUNC_STATIC const int lbits = 9;          /* bits in base literal/length lookup table */
-FUNC_STATIC const int dbits = 6;          /* bits in base distance lookup table */
-
-
-/* If BMAX needs to be larger than 16, then h and x[] should be ulg. */
-#define BMAX 16         /* maximum bit length of any code (16 for explode) */
-#define N_MAX 288       /* maximum number of codes in any set */
-
-
-FUNC_STATIC unsigned hufts;         /* track memory usage */
-
-
-FUNC_STATIC int huft_build(b, n, s, d, e, t, m)
-unsigned *b;            /* code lengths in bits (all assumed <= BMAX) */
-unsigned n;             /* number of codes (assumed <= N_MAX) */
-unsigned s;             /* number of simple-valued codes (0..s-1) */
-const ush *d;                 /* list of base values for non-simple codes */
-const ush *e;                 /* list of extra bits for non-simple codes */
-struct huft **t;        /* result: starting table */
-int *m;                 /* maximum lookup bits, returns actual */
-/* Given a list of code lengths and a maximum table size, make a set of
-   tables to decode that set of codes.  Return zero on success, one if
-   the given code set is incomplete (the tables are still built in this
-   case), two if the input is invalid (all zero length codes or an
-   oversubscribed set of lengths), and three if not enough memory. */
-{
-  unsigned a;                   /* counter for codes of length k */
-  unsigned c[BMAX+1];           /* bit length count table */
-  unsigned f;                   /* i repeats in table every f entries */
-  int g;                        /* maximum code length */
-  int h;                        /* table level */
-  register unsigned i;          /* counter, current code */
-  register unsigned j;          /* counter */
-  register int k;               /* number of bits in current code */
-  int l;                        /* bits per table (returned in m) */
-  register unsigned *p;         /* pointer into c[], b[], or v[] */
-  register struct huft *q;      /* points to current table */
-  struct huft r;                /* table entry for structure assignment */
-  struct huft *u[BMAX];         /* table stack */
-  unsigned v[N_MAX];            /* values in order of bit length */
-  register int w;               /* bits before this table == (l * h) */
-  unsigned x[BMAX+1];           /* bit offsets, then code stack */
-  unsigned *xp;                 /* pointer into x */
-  int y;                        /* number of dummy codes added */
-  unsigned z;                   /* number of entries in current table */
-
-DEBG("huft1 ");
-
-  /* Generate counts for each bit length */
-  memzero(c, sizeof(c));
-
-  p = b;  i = n;
-  do {
-    Tracecv(*p, (stderr, (n-i >= ' ' && n-i <= '~' ? "%c %d\n" : "0x%x %d\n"), 
-           n-i, *p));
-    c[*p]++;                    /* assume all entries <= BMAX */
-    p++;                      /* Can't combine with above line (Solaris bug) */
-  } while (--i);
-  if (c[0] == n)                /* null input--all zero length codes */
-  {
-    *t = (struct huft *)NULL;
-    *m = 0;
-    return 0;
-  }
-
-DEBG("huft2 ");
-
-  /* Find minimum and maximum length, bound *m by those */
-  l = *m;
-  for (j = 1; j <= BMAX; j++)
-    if (c[j])
-      break;
-  k = j;                        /* minimum code length */
-  if ((unsigned)l < j)
-    l = j;
-  for (i = BMAX; i; i--)
-    if (c[i])
-      break;
-  g = i;                        /* maximum code length */
-  if ((unsigned)l > i)
-    l = i;
-  *m = l;
-
-DEBG("huft3 ");
-
-  /* Adjust last length count to fill out codes, if needed */
-  for (y = 1 << j; j < i; j++, y <<= 1)
-    if ((y -= c[j]) < 0)
-      return 2;                 /* bad input: more codes than bits */
-  if ((y -= c[i]) < 0)
-    return 2;
-  c[i] += y;
-
-DEBG("huft4 ");
-
-  /* Generate starting offsets into the value table for each length */
-  x[1] = j = 0;
-  p = c + 1;  xp = x + 2;
-  while (--i) {                 /* note that i == g from above */
-    *xp++ = (j += *p++);
-  }
-
-DEBG("huft5 ");
-
-  /* Make a table of values in order of bit lengths */
-  p = b;  i = 0;
-  do {
-    if ((j = *p++) != 0)
-      v[x[j]++] = i;
-  } while (++i < n);
-
-DEBG("h6 ");
-
-  /* Generate the Huffman codes and for each, make the table entries */
-  x[0] = i = 0;                 /* first Huffman code is zero */
-  p = v;                        /* grab values in bit order */
-  h = -1;                       /* no tables yet--level -1 */
-  w = -l;                       /* bits decoded == (l * h) */
-  u[0] = (struct huft *)NULL;   /* just to keep compilers happy */
-  q = (struct huft *)NULL;      /* ditto */
-  z = 0;                        /* ditto */
-DEBG("h6a ");
-
-  /* go through the bit lengths (k already is bits in shortest code) */
-  for (; k <= g; k++)
-  {
-DEBG("h6b ");
-    a = c[k];
-    while (a--)
-    {
-DEBG("h6b1 ");
-      /* here i is the Huffman code of length k bits for value *p */
-      /* make tables up to required level */
-      while (k > w + l)
-      {
-DEBG1("1 ");
-        h++;
-        w += l;                 /* previous table always l bits */
-
-        /* compute minimum size table less than or equal to l bits */
-        z = (z = g - w) > (unsigned)l ? l : z;  /* upper limit on table size */
-        if ((f = 1 << (j = k - w)) > a + 1)     /* try a k-w bit table */
-        {                       /* too few codes for k-w bit table */
-DEBG1("2 ");
-          f -= a + 1;           /* deduct codes from patterns left */
-          xp = c + k;
-          while (++j < z)       /* try smaller tables up to z bits */
-          {
-            if ((f <<= 1) <= *++xp)
-              break;            /* enough codes to use up j bits */
-            f -= *xp;           /* else deduct codes from patterns */
-          }
-        }
-DEBG1("3 ");
-        z = 1 << j;             /* table entries for j-bit table */
-
-        /* allocate and link in new table */
-        if ((q = (struct huft *)gzip_malloc((z + 1)*sizeof(struct huft))) ==
-            (struct huft *)NULL)
-        {
-          if (h)
-            huft_free(u[0]);
-          return 3;             /* not enough memory */
-        }
-DEBG1("4 ");
-        hufts += z + 1;         /* track memory usage */
-        *t = q + 1;             /* link to list for huft_free() */
-        *(t = &(q->v.t)) = (struct huft *)NULL;
-        u[h] = ++q;             /* table starts after link */
-
-DEBG1("5 ");
-        /* connect to last table, if there is one */
-        if (h)
-        {
-          x[h] = i;             /* save pattern for backing up */
-          r.b = (uch)l;         /* bits to dump before this table */
-          r.e = (uch)(16 + j);  /* bits in this table */
-          r.v.t = q;            /* pointer to this table */
-          j = i >> (w - l);     /* (get around Turbo C bug) */
-          u[h-1][j] = r;        /* connect to last table */
-        }
-DEBG1("6 ");
-      }
-DEBG("h6c ");
-
-      /* set up table entry in r */
-      r.b = (uch)(k - w);
-      if (p >= v + n)
-        r.e = 99;               /* out of values--invalid code */
-      else if (*p < s)
-      {
-        r.e = (uch)(*p < 256 ? 16 : 15);    /* 256 is end-of-block code */
-        r.v.n = (ush)(*p);             /* simple code is just the value */
-       p++;                           /* one compiler does not like *p++ */
-      }
-      else
-      {
-        r.e = (uch)e[*p - s];   /* non-simple--look up in lists */
-        r.v.n = d[*p++ - s];
-      }
-DEBG("h6d ");
-
-      /* fill code-like entries with r */
-      f = 1 << (k - w);
-      for (j = i >> w; j < z; j += f)
-        q[j] = r;
-
-      /* backwards increment the k-bit code i */
-      for (j = 1 << (k - 1); i & j; j >>= 1)
-        i ^= j;
-      i ^= j;
-
-      /* backup over finished tables */
-      while ((i & ((1 << w) - 1)) != x[h])
-      {
-        h--;                    /* don't need to update q */
-        w -= l;
-      }
-DEBG("h6e ");
-    }
-DEBG("h6f ");
-  }
-
-DEBG("huft7 ");
-
-  /* Return true (1) if we were given an incomplete table */
-  return y != 0 && g != 1;
-}
-
-
-
-FUNC_STATIC int huft_free(t)
-struct huft *t;         /* table to free */
-/* Free the malloc'ed tables built by huft_build(), which makes a linked
-   list of the tables it made, with the links in a dummy first entry of
-   each table. */
-{
-  register struct huft *p, *q;
-
-
-  /* Go through linked list, freeing from the malloced (t[-1]) address. */
-  p = t;
-  while (p != (struct huft *)NULL)
-  {
-    q = (--p)->v.t;
-    gzip_free((char*)p);
-    p = q;
-  } 
-  return 0;
-}
-
-
-FUNC_STATIC int inflate_codes(tl, td, bl, bd)
-struct huft *tl, *td;   /* literal/length and distance decoder tables */
-int bl, bd;             /* number of bits decoded by tl[] and td[] */
-/* inflate (decompress) the codes in a deflated (compressed) block.
-   Return an error code or zero if it all goes ok. */
-{
-  register unsigned e;  /* table entry flag/number of extra bits */
-  unsigned n, d;        /* length and index for copy */
-  unsigned w;           /* current window position */
-  struct huft *t;       /* pointer to table entry */
-  unsigned ml, md;      /* masks for bl and bd bits */
-  register ulg b;       /* bit buffer */
-  register unsigned k;  /* number of bits in bit buffer */
-
-
-  /* make local copies of globals */
-  b = bb;                       /* initialize bit buffer */
-  k = bk;
-  w = wp;                       /* initialize window position */
-
-  /* inflate the coded data */
-  ml = mask_bits[bl];           /* precompute masks for speed */
-  md = mask_bits[bd];
-  for (;;)                      /* do until end of block */
-  {
-    NEEDBITS((unsigned)bl)
-    if ((e = (t = tl + ((unsigned)b & ml))->e) > 16)
-      do {
-        if (e == 99)
-          return 1;
-        DUMPBITS(t->b)
-        e -= 16;
-        NEEDBITS(e)
-      } while ((e = (t = t->v.t + ((unsigned)b & mask_bits[e]))->e) > 16);
-    DUMPBITS(t->b)
-    if (e == 16)                /* then it's a literal */
-    {
-      slide[w++] = (uch)t->v.n;
-      Tracevv((stderr, "%c", slide[w-1]));
-      if (w == WSIZE)
-      {
-        flush_output(w);
-        w = 0;
-      }
-    }
-    else                        /* it's an EOB or a length */
-    {
-      /* exit if end of block */
-      if (e == 15)
-        break;
-
-      /* get length of block to copy */
-      NEEDBITS(e)
-      n = t->v.n + ((unsigned)b & mask_bits[e]);
-      DUMPBITS(e);
-
-      /* decode distance of block to copy */
-      NEEDBITS((unsigned)bd)
-      if ((e = (t = td + ((unsigned)b & md))->e) > 16)
-        do {
-          if (e == 99)
-            return 1;
-          DUMPBITS(t->b)
-          e -= 16;
-          NEEDBITS(e)
-        } while ((e = (t = t->v.t + ((unsigned)b & mask_bits[e]))->e) > 16);
-      DUMPBITS(t->b)
-      NEEDBITS(e)
-      d = w - t->v.n - ((unsigned)b & mask_bits[e]);
-      DUMPBITS(e)
-      Tracevv((stderr,"\\[%d,%d]", w-d, n));
-
-      /* do the copy */
-      do {
-        n -= (e = (e = WSIZE - ((d &= WSIZE-1) > w ? d : w)) > n ? n : e);
-#if !defined(NOMEMCPY) && !defined(INFLATE_DEBUG)
-        if (w - d >= e)         /* (this test assumes unsigned comparison) */
-        {
-          memcpy(slide + w, slide + d, e);
-          w += e;
-          d += e;
-        }
-        else                      /* do it slow to avoid memcpy() overlap */
-#endif /* !NOMEMCPY */
-          do {
-            slide[w++] = slide[d++];
-           Tracevv((stderr, "%c", slide[w-1]));
-          } while (--e);
-        if (w == WSIZE)
-        {
-          flush_output(w);
-          w = 0;
-        }
-      } while (n);
-    }
-  }
-
-
-  /* restore the globals from the locals */
-  wp = w;                       /* restore global window pointer */
-  bb = b;                       /* restore global bit buffer */
-  bk = k;
-
-  /* done */
-  return 0;
-}
-
-
-
-FUNC_STATIC int inflate_stored()
-/* "decompress" an inflated type 0 (stored) block. */
-{
-  unsigned n;           /* number of bytes in block */
-  unsigned w;           /* current window position */
-  register ulg b;       /* bit buffer */
-  register unsigned k;  /* number of bits in bit buffer */
-
-DEBG("<stor");
-
-  /* make local copies of globals */
-  b = bb;                       /* initialize bit buffer */
-  k = bk;
-  w = wp;                       /* initialize window position */
-
-
-  /* go to byte boundary */
-  n = k & 7;
-  DUMPBITS(n);
-
-
-  /* get the length and its complement */
-  NEEDBITS(16)
-  n = ((unsigned)b & 0xffff);
-  DUMPBITS(16)
-  NEEDBITS(16)
-  if (n != (unsigned)((~b) & 0xffff))
-    return 1;                   /* error in compressed data */
-  DUMPBITS(16)
-
-
-  /* read and output the compressed data */
-  while (n--)
-  {
-    NEEDBITS(8)
-    slide[w++] = (uch)b;
-    if (w == WSIZE)
-    {
-      flush_output(w);
-      w = 0;
-    }
-    DUMPBITS(8)
-  }
-
-
-  /* restore the globals from the locals */
-  wp = w;                       /* restore global window pointer */
-  bb = b;                       /* restore global bit buffer */
-  bk = k;
-
-  DEBG(">");
-  return 0;
-}
-
-
-
-FUNC_STATIC int inflate_fixed()
-/* decompress an inflated type 1 (fixed Huffman codes) block.  We should
-   either replace this with a custom decoder, or at least precompute the
-   Huffman tables. */
-{
-  int i;                /* temporary variable */
-  struct huft *tl;      /* literal/length code table */
-  struct huft *td;      /* distance code table */
-  int bl;               /* lookup bits for tl */
-  int bd;               /* lookup bits for td */
-  unsigned l[288];      /* length list for huft_build */
-
-DEBG("<fix");
-
-  /* set up literal table */
-  for (i = 0; i < 144; i++)
-    l[i] = 8;
-  for (; i < 256; i++)
-    l[i] = 9;
-  for (; i < 280; i++)
-    l[i] = 7;
-  for (; i < 288; i++)          /* make a complete, but wrong code set */
-    l[i] = 8;
-  bl = 7;
-  if ((i = huft_build(l, 288, 257, cplens, cplext, &tl, &bl)) != 0)
-    return i;
-
-
-  /* set up distance table */
-  for (i = 0; i < 30; i++)      /* make an incomplete code set */
-    l[i] = 5;
-  bd = 5;
-  if ((i = huft_build(l, 30, 0, cpdist, cpdext, &td, &bd)) > 1)
-  {
-    huft_free(tl);
-
-    DEBG(">");
-    return i;
-  }
-
-
-  /* decompress until an end-of-block code */
-  if (inflate_codes(tl, td, bl, bd))
-    return 1;
-
-
-  /* free the decoding tables, return */
-  huft_free(tl);
-  huft_free(td);
-  return 0;
-}
-
-
-
-FUNC_STATIC int inflate_dynamic()
-/* decompress an inflated type 2 (dynamic Huffman codes) block. */
-{
-  int i;                /* temporary variables */
-  unsigned j;
-  unsigned l;           /* last length */
-  unsigned m;           /* mask for bit lengths table */
-  unsigned n;           /* number of lengths to get */
-  struct huft *tl;      /* literal/length code table */
-  struct huft *td;      /* distance code table */
-  int bl;               /* lookup bits for tl */
-  int bd;               /* lookup bits for td */
-  unsigned nb;          /* number of bit length codes */
-  unsigned nl;          /* number of literal/length codes */
-  unsigned nd;          /* number of distance codes */
-#ifdef PKZIP_BUG_WORKAROUND
-  unsigned ll[288+32];  /* literal/length and distance code lengths */
-#else
-  unsigned ll[286+30];  /* literal/length and distance code lengths */
-#endif
-  register ulg b;       /* bit buffer */
-  register unsigned k;  /* number of bits in bit buffer */
-
-DEBG("<dyn");
-
-  /* make local bit buffer */
-  b = bb;
-  k = bk;
-
-
-  /* read in table lengths */
-  NEEDBITS(5)
-  nl = 257 + ((unsigned)b & 0x1f);      /* number of literal/length codes */
-  DUMPBITS(5)
-  NEEDBITS(5)
-  nd = 1 + ((unsigned)b & 0x1f);        /* number of distance codes */
-  DUMPBITS(5)
-  NEEDBITS(4)
-  nb = 4 + ((unsigned)b & 0xf);         /* number of bit length codes */
-  DUMPBITS(4)
-#ifdef PKZIP_BUG_WORKAROUND
-  if (nl > 288 || nd > 32)
-#else
-  if (nl > 286 || nd > 30)
-#endif
-    return 1;                   /* bad lengths */
-
-DEBG("dyn1 ");
-
-  /* read in bit-length-code lengths */
-  for (j = 0; j < nb; j++)
-  {
-    NEEDBITS(3)
-    ll[border[j]] = (unsigned)b & 7;
-    DUMPBITS(3)
-  }
-  for (; j < 19; j++)
-    ll[border[j]] = 0;
-
-DEBG("dyn2 ");
-
-  /* build decoding table for trees--single level, 7 bit lookup */
-  bl = 7;
-  if ((i = huft_build(ll, 19, 19, NULL, NULL, &tl, &bl)) != 0)
-  {
-    if (i == 1)
-      huft_free(tl);
-    return i;                   /* incomplete code set */
-  }
-
-DEBG("dyn3 ");
-
-  /* read in literal and distance code lengths */
-  n = nl + nd;
-  m = mask_bits[bl];
-  i = l = 0;
-  while ((unsigned)i < n)
-  {
-    NEEDBITS((unsigned)bl)
-    j = (td = tl + ((unsigned)b & m))->b;
-    DUMPBITS(j)
-    j = td->v.n;
-    if (j < 16)                 /* length of code in bits (0..15) */
-      ll[i++] = l = j;          /* save last length in l */
-    else if (j == 16)           /* repeat last length 3 to 6 times */
-    {
-      NEEDBITS(2)
-      j = 3 + ((unsigned)b & 3);
-      DUMPBITS(2)
-      if ((unsigned)i + j > n)
-        return 1;
-      while (j--)
-        ll[i++] = l;
-    }
-    else if (j == 17)           /* 3 to 10 zero length codes */
-    {
-      NEEDBITS(3)
-      j = 3 + ((unsigned)b & 7);
-      DUMPBITS(3)
-      if ((unsigned)i + j > n)
-        return 1;
-      while (j--)
-        ll[i++] = 0;
-      l = 0;
-    }
-    else                        /* j == 18: 11 to 138 zero length codes */
-    {
-      NEEDBITS(7)
-      j = 11 + ((unsigned)b & 0x7f);
-      DUMPBITS(7)
-      if ((unsigned)i + j > n)
-        return 1;
-      while (j--)
-        ll[i++] = 0;
-      l = 0;
-    }
-  }
-
-DEBG("dyn4 ");
-
-  /* free decoding table for trees */
-  huft_free(tl);
-
-DEBG("dyn5 ");
-
-  /* restore the global bit buffer */
-  bb = b;
-  bk = k;
-
-DEBG("dyn5a ");
-
-  /* build the decoding tables for literal/length and distance codes */
-  bl = lbits;
-  if ((i = huft_build(ll, nl, 257, cplens, cplext, &tl, &bl)) != 0)
-  {
-DEBG("dyn5b ");
-    if (i == 1) {
-      error(" incomplete literal tree\n");
-      huft_free(tl);
-    }
-    return i;                   /* incomplete code set */
-  }
-DEBG("dyn5c ");
-  bd = dbits;
-  if ((i = huft_build(ll + nl, nd, 0, cpdist, cpdext, &td, &bd)) != 0)
-  {
-DEBG("dyn5d ");
-    if (i == 1) {
-      error(" incomplete distance tree\n");
-#ifdef PKZIP_BUG_WORKAROUND
-      i = 0;
-    }
-#else
-      huft_free(td);
-    }
-    huft_free(tl);
-    return i;                   /* incomplete code set */
-#endif
-  }
-
-DEBG("dyn6 ");
-
-  /* decompress until an end-of-block code */
-  if (inflate_codes(tl, td, bl, bd))
-    return 1;
-
-DEBG("dyn7 ");
-
-  /* free the decoding tables, return */
-  huft_free(tl);
-  huft_free(td);
-
-  DEBG(">");
-  return 0;
-}
-
-
-
-FUNC_STATIC int inflate_block(e)
-int *e;                 /* last block flag */
-/* decompress an inflated block */
-{
-  unsigned t;           /* block type */
-  register ulg b;       /* bit buffer */
-  register unsigned k;  /* number of bits in bit buffer */
-
-  DEBG("<blk");
-
-  /* make local bit buffer */
-  b = bb;
-  k = bk;
-
-
-  /* read in last block bit */
-  NEEDBITS(1)
-  *e = (int)b & 1;
-  DUMPBITS(1)
-
-
-  /* read in block type */
-  NEEDBITS(2)
-  t = (unsigned)b & 3;
-  DUMPBITS(2)
-
-
-  /* restore the global bit buffer */
-  bb = b;
-  bk = k;
-
-  /* inflate that block type */
-  if (t == 2)
-    return inflate_dynamic();
-  if (t == 0)
-    return inflate_stored();
-  if (t == 1)
-    return inflate_fixed();
-
-  DEBG(">");
-
-  /* bad block type */
-  return 2;
-}
-
-
-
-FUNC_STATIC int inflate()
-/* decompress an inflated entry */
-{
-  int e;                /* last block flag */
-  int r;                /* result code */
-  unsigned h;           /* maximum struct huft's malloc'ed */
-
-  /* initialize window, bit buffer */
-  wp = 0;
-  bk = 0;
-  bb = 0;
-
-
-  /* decompress until the last block */
-  h = 0;
-  do {
-    hufts = 0;
-    if ((r = inflate_block(&e)) != 0) {
-      return r;
-    }
-    if (hufts > h)
-      h = hufts;
-  } while (!e);
-
-  /* Undo too much lookahead. The next read will be byte aligned so we
-   * can discard unused bits in the last meaningful byte.
-   */
-  while (bk >= 8) {
-    bk -= 8;
-    inptr--;
-  }
-
-  /* flush out slide */
-  flush_output(wp);
-
-
-  /* return success */
-#ifdef INFLATE_DEBUG
-#ifdef EFI_COMPILE
-  Print(L"<%d> ", h);
-#else
-  printf("<%d> ", h);
-#endif
-#endif /* INFLATE_DEBUG */
-  return 0;
-}
-
-/**********************************************************************
- *
- * The following are support routines for inflate.c
- *
- **********************************************************************/
-
-static ulg crc_32_tab[256];
-static ulg crc;                /* initialized in makecrc() so it'll reside in bss */
-#define CRC_VALUE (crc ^ 0xffffffffUL)
-
-/*
- * Code to compute the CRC-32 table. Borrowed from 
- * gzip-1.0.3/makecrc.c.
- */
-
-static void
-makecrc(void)
-{
-/* Not copyrighted 1990 Mark Adler     */
-
-  unsigned long c;      /* crc shift register */
-  unsigned long e;      /* polynomial exclusive-or pattern */
-  int i;                /* counter for all possible eight bit values */
-  int k;                /* byte being shifted into crc apparatus */
-
-  /* terms of polynomial defining this crc (except x^32): */
-  static const int p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};
-
-  /* Make exclusive-or pattern from polynomial */
-  e = 0;
-  for (i = 0; i < sizeof(p)/sizeof(int); i++)
-    e |= 1L << (31 - p[i]);
-
-  crc_32_tab[0] = 0;
-
-  for (i = 1; i < 256; i++)
-  {
-    c = 0;
-    for (k = i | 256; k != 1; k >>= 1)
-    {
-      c = c & 1 ? (c >> 1) ^ e : c >> 1;
-      if (k & 1)
-        c ^= e;
-    }
-    crc_32_tab[i] = c;
-  }
-
-  /* this is initialized here so this code could reside in ROM */
-  crc = (ulg)0xffffffffUL; /* shift register contents */
-}
-
-/* gzip flag byte */
-#define ASCII_FLAG   0x01 /* bit 0 set: file probably ASCII text */
-#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
-#define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
-#define ORIG_NAME    0x08 /* bit 3 set: original file name present */
-#define COMMENT      0x10 /* bit 4 set: file comment present */
-#define ENCRYPTED    0x20 /* bit 5 set: file is encrypted */
-#define RESERVED     0xC0 /* bit 6,7:   reserved */
-
-/*
- * check for valid gzip signature
- * return:
- *     0 : valid gzip archive
- *     -1: invalid gzip archive
- */
-int
-gzip_probe(uch *buf, unsigned long size)
-{
-    if (size < 4) return -1;
-
-    if (buf[0] != 037 ||
-       ((buf[1] != 0213) && (buf[1] != 0236))) return -1;
-
-    /* We only support method #8, DEFLATED */
-    if (buf[2] != 8) return -1;
-    
-    if ((buf[3] & ENCRYPTED) != 0) return -1;
-
-    if ((buf[3] & CONTINUATION) != 0) return -1;
-
-    if ((buf[3] & RESERVED) != 0) return -1;
-
-    return 0;
-}
-
-
-/*
- * Do the uncompression!
- */
-static int gunzip(void)
-{
-    uch flags;
-    unsigned char magic[2]; /* magic header */
-    char method;
-    ulg orig_crc = 0;       /* original crc */
-    ulg orig_len = 0;       /* original uncompressed length */
-    int res;
-
-    magic[0] = (unsigned char)get_byte();
-    magic[1] = (unsigned char)get_byte();
-    method = (unsigned char)get_byte();
-
-    if (magic[0] != 037 ||
-       ((magic[1] != 0213) && (magic[1] != 0236))) {
-           error("bad gzip magic numbers");
-           return -1;
-    }
-
-    /* We only support method #8, DEFLATED */
-    if (method != 8)  {
-           error("internal error, invalid method");
-           return -1;
-    }
-
-    flags  = (uch)get_byte();
-    if ((flags & ENCRYPTED) != 0) {
-           error("Input is encrypted\n");
-           return -1;
-    }
-    if ((flags & CONTINUATION) != 0) {
-           error("Multi part input\n");
-           return -1;
-    }
-    if ((flags & RESERVED) != 0) {
-           error("Input has invalid flags\n");
-           return -1;
-    }
-    (ulg)get_byte();   /* Get timestamp */
-    ((ulg)get_byte()) << 8;
-    ((ulg)get_byte()) << 16;
-    ((ulg)get_byte()) << 24;
-
-    (void)get_byte();  /* Ignore extra flags for the moment */
-    (void)get_byte();  /* Ignore OS type for the moment */
-
-    if ((flags & EXTRA_FIELD) != 0) {
-           unsigned len = (unsigned)get_byte();
-           len |= ((unsigned)get_byte())<<8;
-           while (len--) (void)get_byte();
-    }
-
-    /* Get original file name if it was truncated */
-    if ((flags & ORIG_NAME) != 0) {
-           /* Discard the old name */
-           while (get_byte() != 0) /* null */ ;
-    } 
-
-    /* Discard file comment if any */
-    if ((flags & COMMENT) != 0) {
-           while (get_byte() != 0) /* null */ ;
-    }
-
-    /* Decompress */
-    if ((res = inflate())) {
-           switch (res) {
-           case 0:
-                   break;
-           case 1:
-                   error("invalid compressed format (err=1)");
-                   break;
-           case 2:
-                   error("invalid compressed format (err=2)");
-                   break;
-           case 3:
-                   error("out of memory");
-                   break;
-           default:
-                   error("invalid compressed format (other)");
-           }
-           return -1;
-    }
-           
-    /* Get the crc and original length */
-    /* crc32  (see algorithm.doc)
-     * uncompressed input size modulo 2^32
-     */
-    orig_crc = (ulg) get_byte();
-    orig_crc |= (ulg) get_byte() << 8;
-    orig_crc |= (ulg) get_byte() << 16;
-    orig_crc |= (ulg) get_byte() << 24;
-    
-    orig_len = (ulg) get_byte();
-    orig_len |= (ulg) get_byte() << 8;
-    orig_len |= (ulg) get_byte() << 16;
-    orig_len |= (ulg) get_byte() << 24;
-    
-    /* Validate decompression */
-    if (orig_crc != CRC_VALUE) {
-           error("crc error");
-           return -1;
-    }
-    if (orig_len != bytes_out) {
-           error("length error");
-           return -1;
-    }
-    return 0;
-}
-
-
index 92d009ef78b5ed7ee4c914fcfe60a43c66e4cf62..150f7a0154bdbe79b712d19e75c13f03bf19281d 100644 (file)
@@ -288,7 +288,7 @@ load_elf(fops_fd_t fd, kdesc_t *kd)
        if (alloc_kmem(low_addr, pages) == -1) {
                VOID *new_addr;
 
-               ERR_PRT((L"%s : AllocatePages(%d, 0x%lx) for kernel failed\n", LD_NAME, pages, low_addr));
+               VERB_PRT(1, (L"%s : AllocatePages(%d, 0x%lx) for kernel failed\n", LD_NAME, pages, low_addr));
 
                if (ia64_can_relocate() == 0) {
                        ERR_PRT((L"relocation is disabled, cannot load kernel"));
@@ -387,6 +387,8 @@ load_elf(fops_fd_t fd, kdesc_t *kd)
                ret = read_file(fd, filesz, (CHAR8 *)phdrs[i].p_paddr);
                if (ret == ELILO_LOAD_ABORTED) goto load_abort;
                if (ret == ELILO_LOAD_ERROR) goto out;
+               if (bswap32(phdrs[i].p_flags) & PF_X)
+                       flush_dcache ((CHAR8 *)phdrs[i].p_paddr, filesz);
 
                /*
                 * update file position
index bb09fafe3f590551e1fa72acc3d0b18c22ea7c49..c8f34c7e7a634cfe0040e70b317985ddd43c4bc4 100644 (file)
@@ -31,5 +31,7 @@ extern INTN query_fpswa(VOID **);
 
 extern INTN ia64_can_relocate();
 
+extern void flush_dcache (CHAR8 *addr, UINT64 len);
+
 #endif /* __ELILO_PRIVATE_IA64_H__ */
 
index ce7e67c8395c748c42d8d17b052ab5a4c64efdb3..4bc2103b79b8bc21e6f8e398b140b156335f5af8 100644 (file)
@@ -78,6 +78,7 @@ setjmp:
 
        /* __sigsetjmp(__jmp_buf buf, int savemask) */
 
+       .proc __sigsetjmp
 __sigsetjmp:
        //.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(2)
        alloc loc1=ar.pfs,2,2,2,0
index ab447fb0372898936ff56292ba427b80e43009df..e11e6b729a95d63f4b388775b114ccd3243caee3 100644 (file)
@@ -65,8 +65,11 @@ typedef struct ia64_boot_params {
        UINTN initrd_start;             /* virtual address where the initial ramdisk begins */
        UINTN initrd_size;              /* how big is the initial ramdisk */
 
+       UINTN vmcode_start;             /* virtual address where the boot time vmcode begins */
+       UINTN vmcode_size;              /* how big is the boot module */
        UINTN loader_addr;              /* start address of boot loader */
        UINTN loader_size;              /* size of loader code & data */
+
 } boot_params_t;
 
 typedef struct sys_img_options {
index 388d435cb72b7e1cf3f788e43221c37e88558348..bb826ef26674cf8f8488d657610b4c96da7520ac 100644 (file)
@@ -39,7 +39,7 @@ extern loader_ops_t plain_loader, gzip_loader;
  * IA-64 specific boot paramters initialization routine
  */
 INTN
-sysdeps_create_boot_params(boot_params_t *bp, CHAR8 *cmdline, memdesc_t *initrd, UINTN *cookie)
+sysdeps_create_boot_params(boot_params_t *bp, CHAR8 *cmdline, memdesc_t *initrd, memdesc_t *vmcode, UINTN *cookie)
 {
        UINTN cols, rows;
        SIMPLE_TEXT_OUTPUT_INTERFACE *conout;
@@ -64,7 +64,12 @@ sysdeps_create_boot_params(boot_params_t *bp, CHAR8 *cmdline, memdesc_t *initrd,
        bp->efi_memdesc_version = mdesc.desc_version;
        bp->command_line        = (UINTN)cmdline;
        bp->initrd_start        = (UINTN) initrd->start_addr;
-       bp->initrd_size         = initrd->pgcnt << EFI_PAGE_SHIFT;
+       bp->initrd_size         = initrd->size;
+       DBG_PRT((L"Got initrd @ 0x%lx (%d bytes)", initrd->start_addr, initrd->size));
+
+       bp->vmcode_start        = (UINTN) vmcode->start_addr;
+       bp->vmcode_size         = vmcode->size;
+       DBG_PRT((L"Got vmcode @ 0x%lx (%d bytes)", vmcode->start_addr, vmcode->size));
 
        /* fetch console parameters: */
        conout = systab->ConOut;
@@ -135,3 +140,20 @@ sysdeps_initrd_get_addr(kdesc_t *kd, memdesc_t *imem)
        return 0;
 }
 
+/* Flush data cache [addr; addr + len], and sync with icache.  */
+void
+flush_dcache (CHAR8 *addr, UINT64 len)
+{
+       /* Cache line length is at least 32.  */
+       UINT64 a = (UINT64)addr & ~0x1f;
+
+       VERB_PRT(3, Print(L"Flush 0x%lx-", a));
+
+       /* Flush data.  */
+       for (len = (len + 31) & ~0x1f; len > 0; len -= 0x20, a += 0x20)
+               asm volatile ("fc %0" : : "r" (a));
+       /* Sync and serialize.  Maybe extra.  */
+       asm volatile (";; sync.i;; srlz.i;;");
+
+       VERB_PRT(3, Print(L"0x%lx\n", a));
+}
diff --git a/inflate.c b/inflate.c
new file mode 100644 (file)
index 0000000..843c93b
--- /dev/null
+++ b/inflate.c
@@ -0,0 +1,1168 @@
+#define DEBG(x)
+#define DEBG1(x)
+/* inflate.c -- Not copyrighted 1992 by Mark Adler
+   version c10p1, 10 January 1993 */
+
+/* 
+ * Adapted for booting Linux by Hannu Savolainen 1993
+ * based on gzip-1.0.3 
+ *
+ * Nicolas Pitre <nico@cam.org>, 1999/04/14 :
+ *   Little mods for all variable to reside either into rodata or bss segments
+ *   by marking constant variables with 'const' and initializing all the others
+ *   at run-time only.  This allows for the kernel uncompressor to run
+ *   directly from Flash or ROM memory on embeded systems.
+ */
+
+/*
+   Inflate deflated (PKZIP's method 8 compressed) data.  The compression
+   method searches for as much of the current string of bytes (up to a
+   length of 258) in the previous 32 K bytes.  If it doesn't find any
+   matches (of at least length 3), it codes the next byte.  Otherwise, it
+   codes the length of the matched string and its distance backwards from
+   the current position.  There is a single Huffman code that codes both
+   single bytes (called "literals") and match lengths.  A second Huffman
+   code codes the distance information, which follows a length code.  Each
+   length or distance code actually represents a base value and a number
+   of "extra" (sometimes zero) bits to get to add to the base value.  At
+   the end of each deflated block is a special end-of-block (EOB) literal/
+   length code.  The decoding process is basically: get a literal/length
+   code; if EOB then done; if a literal, emit the decoded byte; if a
+   length then get the distance and emit the referred-to bytes from the
+   sliding window of previously emitted data.
+
+   There are (currently) three kinds of inflate blocks: stored, fixed, and
+   dynamic.  The compressor deals with some chunk of data at a time, and
+   decides which method to use on a chunk-by-chunk basis.  A chunk might
+   typically be 32 K or 64 K.  If the chunk is incompressible, then the
+   "stored" method is used.  In this case, the bytes are simply stored as
+   is, eight bits per byte, with none of the above coding.  The bytes are
+   preceded by a count, since there is no longer an EOB code.
+
+   If the data is compressible, then either the fixed or dynamic methods
+   are used.  In the dynamic method, the compressed data is preceded by
+   an encoding of the literal/length and distance Huffman codes that are
+   to be used to decode this block.  The representation is itself Huffman
+   coded, and so is preceded by a description of that code.  These code
+   descriptions take up a little space, and so for small blocks, there is
+   a predefined set of codes, called the fixed codes.  The fixed method is
+   used if the block codes up smaller that way (usually for quite small
+   chunks), otherwise the dynamic method is used.  In the latter case, the
+   codes are customized to the probabilities in the current block, and so
+   can code it much better than the pre-determined fixed codes.
+   The Huffman codes themselves are decoded using a multi-level table
+   lookup, in order to maximize the speed of decoding plus the speed of
+   building the decoding tables.  See the comments below that precede the
+   lbits and dbits tuning parameters.
+ */
+
+
+/*
+   Notes beyond the 1.93a appnote.txt:
+
+   1. Distance pointers never point before the beginning of the output
+      stream.
+   2. Distance pointers can point back across blocks, up to 32k away.
+   3. There is an implied maximum of 7 bits for the bit length table and
+      15 bits for the actual data.
+   4. If only one code exists, then it is encoded using one bit.  (Zero
+      would be more efficient, but perhaps a little confusing.)  If two
+      codes exist, they are coded using one bit each (0 and 1).
+   5. There is no way of sending zero distance codes--a dummy must be
+      sent if there are none.  (History: a pre 2.0 version of PKZIP would
+      store blocks with no distance codes, but this was discovered to be
+      too harsh a criterion.)  Valid only for 1.93a.  2.04c does allow
+      zero distance codes, which is sent as one code of zero bits in
+      length.
+   6. There are up to 286 literal/length codes.  Code 256 represents the
+      end-of-block.  Note however that the static length tree defines
+      288 codes just to fill out the Huffman codes.  Codes 286 and 287
+      cannot be used though, since there is no length base or extra bits
+      defined for them.  Similarly, there are up to 30 distance codes.
+      However, static trees define 32 codes (all 5 bits) to fill out the
+      Huffman codes, but the last two had better not show up in the data.
+   7. Unzip can check dynamic Huffman blocks for complete code sets.
+      The exception is that a single code would not be complete (see #4).
+   8. The five bits following the block type is really the number of
+      literal codes sent minus 257.
+   9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits
+      (1+6+6).  Therefore, to output three times the length, you output
+      three codes (1+1+1), whereas to output four times the same length,
+      you only need two codes (1+3).  Hmm.
+  10. In the tree reconstruction algorithm, Code = Code + Increment
+      only if BitLength(i) is not zero.  (Pretty obvious.)
+  11. Correction: 4 Bits: # of Bit Length codes - 4     (4 - 19)
+  12. Note: length code 284 can represent 227-258, but length code 285
+      really is 258.  The last length deserves its own, short code
+      since it gets used a lot in very redundant files.  The length
+      258 is special since 258 - 3 (the min match length) is 255.
+  13. The literal/length and distance code bit lengths are read as a
+      single stream of lengths.  It is possible (and advantageous) for
+      a repeat code (16, 17, or 18) to go across the boundary between
+      the two sets of lengths.
+ */
+
+#ifdef RCSID
+static char rcsid[] = "#Id: inflate.c,v 0.14 1993/06/10 13:27:04 jloup Exp #";
+#endif
+
+#ifndef FUNC_STATIC
+
+#if defined(STDC_HEADERS) || defined(HAVE_STDLIB_H)
+#  include <sys/types.h>
+#  include <stdlib.h>
+#endif
+
+#include "gzip.h"
+#define FUNC_STATIC
+#endif /* !FUNC_STATIC */
+       
+#define slide window
+
+/* Huffman code lookup table entry--this entry is four bytes for machines
+   that have 16-bit pointers (e.g. PC's in the small or medium model).
+   Valid extra bits are 0..13.  e == 15 is EOB (end of block), e == 16
+   means that v is a literal, 16 < e < 32 means that v is a pointer to
+   the next table, which codes e - 16 bits, and lastly e == 99 indicates
+   an unused code.  If a code with e == 99 is looked up, this implies an
+   error in the data. */
+struct huft {
+  uch e;                /* number of extra bits or operation */
+  uch b;                /* number of bits in this code or subcode */
+  union {
+    ush n;              /* literal, length base, or distance base */
+    struct huft *t;     /* pointer to next level of table */
+  } v;
+};
+
+
+/* Function prototypes */
+FUNC_STATIC int huft_build OF((unsigned *, unsigned, unsigned, 
+               const ush *, const ush *, struct huft **, int *));
+FUNC_STATIC int huft_free OF((struct huft *));
+FUNC_STATIC int inflate_codes OF((struct huft *, struct huft *, int, int));
+FUNC_STATIC int inflate_stored OF((void));
+FUNC_STATIC int inflate_fixed OF((void));
+FUNC_STATIC int inflate_dynamic OF((void));
+FUNC_STATIC int inflate_block OF((int *));
+FUNC_STATIC int inflate OF((void));
+
+
+/* The inflate algorithm uses a sliding 32 K byte window on the uncompressed
+   stream to find repeated byte strings.  This is implemented here as a
+   circular buffer.  The index is updated simply by incrementing and then
+   ANDing with 0x7fff (32K-1). */
+/* It is left to other modules to supply the 32 K area.  It is assumed
+   to be usable as if it were declared "uch slide[32768];" or as just
+   "uch *slide;" and then malloc'ed in the latter case.  The definition
+   must be in unzip.h, included above. */
+/* unsigned wp;             current position in slide */
+#define wp outcnt
+#define flush_output(w) (wp=(w),flush_window())
+
+/* Tables for deflate from PKZIP's appnote.txt. */
+static const unsigned border[] = {    /* Order of the bit length code lengths */
+        16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+static const ush cplens[] = {         /* Copy lengths for literal codes 257..285 */
+        3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+        35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
+        /* note: see note #13 above about the 258 in this list. */
+static const ush cplext[] = {         /* Extra bits for literal codes 257..285 */
+        0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
+        3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99}; /* 99==invalid */
+static const ush cpdist[] = {         /* Copy offsets for distance codes 0..29 */
+        1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+        257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+        8193, 12289, 16385, 24577};
+static const ush cpdext[] = {         /* Extra bits for distance codes */
+        0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
+        7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
+        12, 12, 13, 13};
+
+
+
+/* Macros for inflate() bit peeking and grabbing.
+   The usage is:
+   
+        NEEDBITS(j)
+        x = b & mask_bits[j];
+        DUMPBITS(j)
+
+   where NEEDBITS makes sure that b has at least j bits in it, and
+   DUMPBITS removes the bits from b.  The macros use the variable k
+   for the number of bits in b.  Normally, b and k are register
+   variables for speed, and are initialized at the beginning of a
+   routine that uses these macros from a global bit buffer and count.
+
+   If we assume that EOB will be the longest code, then we will never
+   ask for bits with NEEDBITS that are beyond the end of the stream.
+   So, NEEDBITS should not read any more bytes than are needed to
+   meet the request.  Then no bytes need to be "returned" to the buffer
+   at the end of the last block.
+
+   However, this assumption is not true for fixed blocks--the EOB code
+   is 7 bits, but the other literal/length codes can be 8 or 9 bits.
+   (The EOB code is shorter than other codes because fixed blocks are
+   generally short.  So, while a block always has an EOB, many other
+   literal/length codes have a significantly lower probability of
+   showing up at all.)  However, by making the first table have a
+   lookup of seven bits, the EOB code will be found in that first
+   lookup, and so will not require that too many bits be pulled from
+   the stream.
+ */
+
+FUNC_STATIC ulg bb;                         /* bit buffer */
+FUNC_STATIC unsigned bk;                    /* bits in bit buffer */
+
+FUNC_STATIC const ush mask_bits[] = {
+    0x0000,
+    0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
+    0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
+};
+
+#define NEXTBYTE()  (uch)get_byte()
+#define NEEDBITS(n) {while(k<(n)){b|=((ulg)NEXTBYTE())<<k;k+=8;}}
+#define DUMPBITS(n) {b>>=(n);k-=(n);}
+
+
+/*
+   Huffman code decoding is performed using a multi-level table lookup.
+   The fastest way to decode is to simply build a lookup table whose
+   size is determined by the longest code.  However, the time it takes
+   to build this table can also be a factor if the data being decoded
+   is not very long.  The most common codes are necessarily the
+   shortest codes, so those codes dominate the decoding time, and hence
+   the speed.  The idea is you can have a shorter table that decodes the
+   shorter, more probable codes, and then point to subsidiary tables for
+   the longer codes.  The time it costs to decode the longer codes is
+   then traded against the time it takes to make longer tables.
+
+   This results of this trade are in the variables lbits and dbits
+   below.  lbits is the number of bits the first level table for literal/
+   length codes can decode in one step, and dbits is the same thing for
+   the distance codes.  Subsequent tables are also less than or equal to
+   those sizes.  These values may be adjusted either when all of the
+   codes are shorter than that, in which case the longest code length in
+   bits is used, or when the shortest code is *longer* than the requested
+   table size, in which case the length of the shortest code in bits is
+   used.
+
+   There are two different values for the two tables, since they code a
+   different number of possibilities each.  The literal/length table
+   codes 286 possible values, or in a flat code, a little over eight
+   bits.  The distance table codes 30 possible values, or a little less
+   than five bits, flat.  The optimum values for speed end up being
+   about one bit more than those, so lbits is 8+1 and dbits is 5+1.
+   The optimum values may differ though from machine to machine, and
+   possibly even between compilers.  Your mileage may vary.
+ */
+
+
+FUNC_STATIC const int lbits = 9;          /* bits in base literal/length lookup table */
+FUNC_STATIC const int dbits = 6;          /* bits in base distance lookup table */
+
+
+/* If BMAX needs to be larger than 16, then h and x[] should be ulg. */
+#define BMAX 16         /* maximum bit length of any code (16 for explode) */
+#define N_MAX 288       /* maximum number of codes in any set */
+
+
+FUNC_STATIC unsigned hufts;         /* track memory usage */
+
+
+FUNC_STATIC int huft_build(b, n, s, d, e, t, m)
+unsigned *b;            /* code lengths in bits (all assumed <= BMAX) */
+unsigned n;             /* number of codes (assumed <= N_MAX) */
+unsigned s;             /* number of simple-valued codes (0..s-1) */
+const ush *d;                 /* list of base values for non-simple codes */
+const ush *e;                 /* list of extra bits for non-simple codes */
+struct huft **t;        /* result: starting table */
+int *m;                 /* maximum lookup bits, returns actual */
+/* Given a list of code lengths and a maximum table size, make a set of
+   tables to decode that set of codes.  Return zero on success, one if
+   the given code set is incomplete (the tables are still built in this
+   case), two if the input is invalid (all zero length codes or an
+   oversubscribed set of lengths), and three if not enough memory. */
+{
+  unsigned a;                   /* counter for codes of length k */
+  unsigned c[BMAX+1];           /* bit length count table */
+  unsigned f;                   /* i repeats in table every f entries */
+  int g;                        /* maximum code length */
+  int h;                        /* table level */
+  register unsigned i;          /* counter, current code */
+  register unsigned j;          /* counter */
+  register int k;               /* number of bits in current code */
+  int l;                        /* bits per table (returned in m) */
+  register unsigned *p;         /* pointer into c[], b[], or v[] */
+  register struct huft *q;      /* points to current table */
+  struct huft r;                /* table entry for structure assignment */
+  struct huft *u[BMAX];         /* table stack */
+  unsigned v[N_MAX];            /* values in order of bit length */
+  register int w;               /* bits before this table == (l * h) */
+  unsigned x[BMAX+1];           /* bit offsets, then code stack */
+  unsigned *xp;                 /* pointer into x */
+  int y;                        /* number of dummy codes added */
+  unsigned z;                   /* number of entries in current table */
+
+DEBG("huft1 ");
+
+  /* Generate counts for each bit length */
+  memzero(c, sizeof(c));
+
+  p = b;  i = n;
+  do {
+    Tracecv(*p, (stderr, (n-i >= ' ' && n-i <= '~' ? "%c %d\n" : "0x%x %d\n"), 
+           n-i, *p));
+    c[*p]++;                    /* assume all entries <= BMAX */
+    p++;                      /* Can't combine with above line (Solaris bug) */
+  } while (--i);
+  if (c[0] == n)                /* null input--all zero length codes */
+  {
+    *t = (struct huft *)NULL;
+    *m = 0;
+    return 0;
+  }
+
+DEBG("huft2 ");
+
+  /* Find minimum and maximum length, bound *m by those */
+  l = *m;
+  for (j = 1; j <= BMAX; j++)
+    if (c[j])
+      break;
+  k = j;                        /* minimum code length */
+  if ((unsigned)l < j)
+    l = j;
+  for (i = BMAX; i; i--)
+    if (c[i])
+      break;
+  g = i;                        /* maximum code length */
+  if ((unsigned)l > i)
+    l = i;
+  *m = l;
+
+DEBG("huft3 ");
+
+  /* Adjust last length count to fill out codes, if needed */
+  for (y = 1 << j; j < i; j++, y <<= 1)
+    if ((y -= c[j]) < 0)
+      return 2;                 /* bad input: more codes than bits */
+  if ((y -= c[i]) < 0)
+    return 2;
+  c[i] += y;
+
+DEBG("huft4 ");
+
+  /* Generate starting offsets into the value table for each length */
+  x[1] = j = 0;
+  p = c + 1;  xp = x + 2;
+  while (--i) {                 /* note that i == g from above */
+    *xp++ = (j += *p++);
+  }
+
+DEBG("huft5 ");
+
+  /* Make a table of values in order of bit lengths */
+  p = b;  i = 0;
+  do {
+    if ((j = *p++) != 0)
+      v[x[j]++] = i;
+  } while (++i < n);
+
+DEBG("h6 ");
+
+  /* Generate the Huffman codes and for each, make the table entries */
+  x[0] = i = 0;                 /* first Huffman code is zero */
+  p = v;                        /* grab values in bit order */
+  h = -1;                       /* no tables yet--level -1 */
+  w = -l;                       /* bits decoded == (l * h) */
+  u[0] = (struct huft *)NULL;   /* just to keep compilers happy */
+  q = (struct huft *)NULL;      /* ditto */
+  z = 0;                        /* ditto */
+DEBG("h6a ");
+
+  /* go through the bit lengths (k already is bits in shortest code) */
+  for (; k <= g; k++)
+  {
+DEBG("h6b ");
+    a = c[k];
+    while (a--)
+    {
+DEBG("h6b1 ");
+      /* here i is the Huffman code of length k bits for value *p */
+      /* make tables up to required level */
+      while (k > w + l)
+      {
+DEBG1("1 ");
+        h++;
+        w += l;                 /* previous table always l bits */
+
+        /* compute minimum size table less than or equal to l bits */
+        z = (z = g - w) > (unsigned)l ? l : z;  /* upper limit on table size */
+        if ((f = 1 << (j = k - w)) > a + 1)     /* try a k-w bit table */
+        {                       /* too few codes for k-w bit table */
+DEBG1("2 ");
+          f -= a + 1;           /* deduct codes from patterns left */
+          xp = c + k;
+          while (++j < z)       /* try smaller tables up to z bits */
+          {
+            if ((f <<= 1) <= *++xp)
+              break;            /* enough codes to use up j bits */
+            f -= *xp;           /* else deduct codes from patterns */
+          }
+        }
+DEBG1("3 ");
+        z = 1 << j;             /* table entries for j-bit table */
+
+        /* allocate and link in new table */
+        if ((q = (struct huft *)gzip_malloc((z + 1)*sizeof(struct huft))) ==
+            (struct huft *)NULL)
+        {
+          if (h)
+            huft_free(u[0]);
+          return 3;             /* not enough memory */
+        }
+DEBG1("4 ");
+        hufts += z + 1;         /* track memory usage */
+        *t = q + 1;             /* link to list for huft_free() */
+        *(t = &(q->v.t)) = (struct huft *)NULL;
+        u[h] = ++q;             /* table starts after link */
+
+DEBG1("5 ");
+        /* connect to last table, if there is one */
+        if (h)
+        {
+          x[h] = i;             /* save pattern for backing up */
+          r.b = (uch)l;         /* bits to dump before this table */
+          r.e = (uch)(16 + j);  /* bits in this table */
+          r.v.t = q;            /* pointer to this table */
+          j = i >> (w - l);     /* (get around Turbo C bug) */
+          u[h-1][j] = r;        /* connect to last table */
+        }
+DEBG1("6 ");
+      }
+DEBG("h6c ");
+
+      /* set up table entry in r */
+      r.b = (uch)(k - w);
+      if (p >= v + n)
+        r.e = 99;               /* out of values--invalid code */
+      else if (*p < s)
+      {
+        r.e = (uch)(*p < 256 ? 16 : 15);    /* 256 is end-of-block code */
+        r.v.n = (ush)(*p);             /* simple code is just the value */
+       p++;                           /* one compiler does not like *p++ */
+      }
+      else
+      {
+        r.e = (uch)e[*p - s];   /* non-simple--look up in lists */
+        r.v.n = d[*p++ - s];
+      }
+DEBG("h6d ");
+
+      /* fill code-like entries with r */
+      f = 1 << (k - w);
+      for (j = i >> w; j < z; j += f)
+        q[j] = r;
+
+      /* backwards increment the k-bit code i */
+      for (j = 1 << (k - 1); i & j; j >>= 1)
+        i ^= j;
+      i ^= j;
+
+      /* backup over finished tables */
+      while ((i & ((1 << w) - 1)) != x[h])
+      {
+        h--;                    /* don't need to update q */
+        w -= l;
+      }
+DEBG("h6e ");
+    }
+DEBG("h6f ");
+  }
+
+DEBG("huft7 ");
+
+  /* Return true (1) if we were given an incomplete table */
+  return y != 0 && g != 1;
+}
+
+
+
+FUNC_STATIC int huft_free(t)
+struct huft *t;         /* table to free */
+/* Free the malloc'ed tables built by huft_build(), which makes a linked
+   list of the tables it made, with the links in a dummy first entry of
+   each table. */
+{
+  register struct huft *p, *q;
+
+
+  /* Go through linked list, freeing from the malloced (t[-1]) address. */
+  p = t;
+  while (p != (struct huft *)NULL)
+  {
+    q = (--p)->v.t;
+    gzip_free((char*)p);
+    p = q;
+  } 
+  return 0;
+}
+
+
+FUNC_STATIC int inflate_codes(tl, td, bl, bd)
+struct huft *tl, *td;   /* literal/length and distance decoder tables */
+int bl, bd;             /* number of bits decoded by tl[] and td[] */
+/* inflate (decompress) the codes in a deflated (compressed) block.
+   Return an error code or zero if it all goes ok. */
+{
+  register unsigned e;  /* table entry flag/number of extra bits */
+  unsigned n, d;        /* length and index for copy */
+  unsigned w;           /* current window position */
+  struct huft *t;       /* pointer to table entry */
+  unsigned ml, md;      /* masks for bl and bd bits */
+  register ulg b;       /* bit buffer */
+  register unsigned k;  /* number of bits in bit buffer */
+
+
+  /* make local copies of globals */
+  b = bb;                       /* initialize bit buffer */
+  k = bk;
+  w = wp;                       /* initialize window position */
+
+  /* inflate the coded data */
+  ml = mask_bits[bl];           /* precompute masks for speed */
+  md = mask_bits[bd];
+  for (;;)                      /* do until end of block */
+  {
+    NEEDBITS((unsigned)bl)
+    if ((e = (t = tl + ((unsigned)b & ml))->e) > 16)
+      do {
+        if (e == 99)
+          return 1;
+        DUMPBITS(t->b)
+        e -= 16;
+        NEEDBITS(e)
+      } while ((e = (t = t->v.t + ((unsigned)b & mask_bits[e]))->e) > 16);
+    DUMPBITS(t->b)
+    if (e == 16)                /* then it's a literal */
+    {
+      slide[w++] = (uch)t->v.n;
+      Tracevv((stderr, "%c", slide[w-1]));
+      if (w == WSIZE)
+      {
+        flush_output(w);
+        w = 0;
+      }
+    }
+    else                        /* it's an EOB or a length */
+    {
+      /* exit if end of block */
+      if (e == 15)
+        break;
+
+      /* get length of block to copy */
+      NEEDBITS(e)
+      n = t->v.n + ((unsigned)b & mask_bits[e]);
+      DUMPBITS(e);
+
+      /* decode distance of block to copy */
+      NEEDBITS((unsigned)bd)
+      if ((e = (t = td + ((unsigned)b & md))->e) > 16)
+        do {
+          if (e == 99)
+            return 1;
+          DUMPBITS(t->b)
+          e -= 16;
+          NEEDBITS(e)
+        } while ((e = (t = t->v.t + ((unsigned)b & mask_bits[e]))->e) > 16);
+      DUMPBITS(t->b)
+      NEEDBITS(e)
+      d = w - t->v.n - ((unsigned)b & mask_bits[e]);
+      DUMPBITS(e)
+      Tracevv((stderr,"\\[%d,%d]", w-d, n));
+
+      /* do the copy */
+      do {
+        n -= (e = (e = WSIZE - ((d &= WSIZE-1) > w ? d : w)) > n ? n : e);
+#if !defined(NOMEMCPY) && !defined(INFLATE_DEBUG)
+        if (w - d >= e)         /* (this test assumes unsigned comparison) */
+        {
+          memcpy(slide + w, slide + d, e);
+          w += e;
+          d += e;
+        }
+        else                      /* do it slow to avoid memcpy() overlap */
+#endif /* !NOMEMCPY */
+          do {
+            slide[w++] = slide[d++];
+           Tracevv((stderr, "%c", slide[w-1]));
+          } while (--e);
+        if (w == WSIZE)
+        {
+          flush_output(w);
+          w = 0;
+        }
+      } while (n);
+    }
+  }
+
+
+  /* restore the globals from the locals */
+  wp = w;                       /* restore global window pointer */
+  bb = b;                       /* restore global bit buffer */
+  bk = k;
+
+  /* done */
+  return 0;
+}
+
+
+
+FUNC_STATIC int inflate_stored()
+/* "decompress" an inflated type 0 (stored) block. */
+{
+  unsigned n;           /* number of bytes in block */
+  unsigned w;           /* current window position */
+  register ulg b;       /* bit buffer */
+  register unsigned k;  /* number of bits in bit buffer */
+
+DEBG("<stor");
+
+  /* make local copies of globals */
+  b = bb;                       /* initialize bit buffer */
+  k = bk;
+  w = wp;                       /* initialize window position */
+
+
+  /* go to byte boundary */
+  n = k & 7;
+  DUMPBITS(n);
+
+
+  /* get the length and its complement */
+  NEEDBITS(16)
+  n = ((unsigned)b & 0xffff);
+  DUMPBITS(16)
+  NEEDBITS(16)
+  if (n != (unsigned)((~b) & 0xffff))
+    return 1;                   /* error in compressed data */
+  DUMPBITS(16)
+
+
+  /* read and output the compressed data */
+  while (n--)
+  {
+    NEEDBITS(8)
+    slide[w++] = (uch)b;
+    if (w == WSIZE)
+    {
+      flush_output(w);
+      w = 0;
+    }
+    DUMPBITS(8)
+  }
+
+
+  /* restore the globals from the locals */
+  wp = w;                       /* restore global window pointer */
+  bb = b;                       /* restore global bit buffer */
+  bk = k;
+
+  DEBG(">");
+  return 0;
+}
+
+
+
+FUNC_STATIC int inflate_fixed()
+/* decompress an inflated type 1 (fixed Huffman codes) block.  We should
+   either replace this with a custom decoder, or at least precompute the
+   Huffman tables. */
+{
+  int i;                /* temporary variable */
+  struct huft *tl;      /* literal/length code table */
+  struct huft *td;      /* distance code table */
+  int bl;               /* lookup bits for tl */
+  int bd;               /* lookup bits for td */
+  unsigned l[288];      /* length list for huft_build */
+
+DEBG("<fix");
+
+  /* set up literal table */
+  for (i = 0; i < 144; i++)
+    l[i] = 8;
+  for (; i < 256; i++)
+    l[i] = 9;
+  for (; i < 280; i++)
+    l[i] = 7;
+  for (; i < 288; i++)          /* make a complete, but wrong code set */
+    l[i] = 8;
+  bl = 7;
+  if ((i = huft_build(l, 288, 257, cplens, cplext, &tl, &bl)) != 0)
+    return i;
+
+
+  /* set up distance table */
+  for (i = 0; i < 30; i++)      /* make an incomplete code set */
+    l[i] = 5;
+  bd = 5;
+  if ((i = huft_build(l, 30, 0, cpdist, cpdext, &td, &bd)) > 1)
+  {
+    huft_free(tl);
+
+    DEBG(">");
+    return i;
+  }
+
+
+  /* decompress until an end-of-block code */
+  if (inflate_codes(tl, td, bl, bd))
+    return 1;
+
+
+  /* free the decoding tables, return */
+  huft_free(tl);
+  huft_free(td);
+  return 0;
+}
+
+
+
+FUNC_STATIC int inflate_dynamic()
+/* decompress an inflated type 2 (dynamic Huffman codes) block. */
+{
+  int i;                /* temporary variables */
+  unsigned j;
+  unsigned l;           /* last length */
+  unsigned m;           /* mask for bit lengths table */
+  unsigned n;           /* number of lengths to get */
+  struct huft *tl;      /* literal/length code table */
+  struct huft *td;      /* distance code table */
+  int bl;               /* lookup bits for tl */
+  int bd;               /* lookup bits for td */
+  unsigned nb;          /* number of bit length codes */
+  unsigned nl;          /* number of literal/length codes */
+  unsigned nd;          /* number of distance codes */
+#ifdef PKZIP_BUG_WORKAROUND
+  unsigned ll[288+32];  /* literal/length and distance code lengths */
+#else
+  unsigned ll[286+30];  /* literal/length and distance code lengths */
+#endif
+  register ulg b;       /* bit buffer */
+  register unsigned k;  /* number of bits in bit buffer */
+
+DEBG("<dyn");
+
+  /* make local bit buffer */
+  b = bb;
+  k = bk;
+
+
+  /* read in table lengths */
+  NEEDBITS(5)
+  nl = 257 + ((unsigned)b & 0x1f);      /* number of literal/length codes */
+  DUMPBITS(5)
+  NEEDBITS(5)
+  nd = 1 + ((unsigned)b & 0x1f);        /* number of distance codes */
+  DUMPBITS(5)
+  NEEDBITS(4)
+  nb = 4 + ((unsigned)b & 0xf);         /* number of bit length codes */
+  DUMPBITS(4)
+#ifdef PKZIP_BUG_WORKAROUND
+  if (nl > 288 || nd > 32)
+#else
+  if (nl > 286 || nd > 30)
+#endif
+    return 1;                   /* bad lengths */
+
+DEBG("dyn1 ");
+
+  /* read in bit-length-code lengths */
+  for (j = 0; j < nb; j++)
+  {
+    NEEDBITS(3)
+    ll[border[j]] = (unsigned)b & 7;
+    DUMPBITS(3)
+  }
+  for (; j < 19; j++)
+    ll[border[j]] = 0;
+
+DEBG("dyn2 ");
+
+  /* build decoding table for trees--single level, 7 bit lookup */
+  bl = 7;
+  if ((i = huft_build(ll, 19, 19, NULL, NULL, &tl, &bl)) != 0)
+  {
+    if (i == 1)
+      huft_free(tl);
+    return i;                   /* incomplete code set */
+  }
+
+DEBG("dyn3 ");
+
+  /* read in literal and distance code lengths */
+  n = nl + nd;
+  m = mask_bits[bl];
+  i = l = 0;
+  while ((unsigned)i < n)
+  {
+    NEEDBITS((unsigned)bl)
+    j = (td = tl + ((unsigned)b & m))->b;
+    DUMPBITS(j)
+    j = td->v.n;
+    if (j < 16)                 /* length of code in bits (0..15) */
+      ll[i++] = l = j;          /* save last length in l */
+    else if (j == 16)           /* repeat last length 3 to 6 times */
+    {
+      NEEDBITS(2)
+      j = 3 + ((unsigned)b & 3);
+      DUMPBITS(2)
+      if ((unsigned)i + j > n)
+        return 1;
+      while (j--)
+        ll[i++] = l;
+    }
+    else if (j == 17)           /* 3 to 10 zero length codes */
+    {
+      NEEDBITS(3)
+      j = 3 + ((unsigned)b & 7);
+      DUMPBITS(3)
+      if ((unsigned)i + j > n)
+        return 1;
+      while (j--)
+        ll[i++] = 0;
+      l = 0;
+    }
+    else                        /* j == 18: 11 to 138 zero length codes */
+    {
+      NEEDBITS(7)
+      j = 11 + ((unsigned)b & 0x7f);
+      DUMPBITS(7)
+      if ((unsigned)i + j > n)
+        return 1;
+      while (j--)
+        ll[i++] = 0;
+      l = 0;
+    }
+  }
+
+DEBG("dyn4 ");
+
+  /* free decoding table for trees */
+  huft_free(tl);
+
+DEBG("dyn5 ");
+
+  /* restore the global bit buffer */
+  bb = b;
+  bk = k;
+
+DEBG("dyn5a ");
+
+  /* build the decoding tables for literal/length and distance codes */
+  bl = lbits;
+  if ((i = huft_build(ll, nl, 257, cplens, cplext, &tl, &bl)) != 0)
+  {
+DEBG("dyn5b ");
+    if (i == 1) {
+      error(" incomplete literal tree\n");
+      huft_free(tl);
+    }
+    return i;                   /* incomplete code set */
+  }
+DEBG("dyn5c ");
+  bd = dbits;
+  if ((i = huft_build(ll + nl, nd, 0, cpdist, cpdext, &td, &bd)) != 0)
+  {
+DEBG("dyn5d ");
+    if (i == 1) {
+      error(" incomplete distance tree\n");
+#ifdef PKZIP_BUG_WORKAROUND
+      i = 0;
+    }
+#else
+      huft_free(td);
+    }
+    huft_free(tl);
+    return i;                   /* incomplete code set */
+#endif
+  }
+
+DEBG("dyn6 ");
+
+  /* decompress until an end-of-block code */
+  if (inflate_codes(tl, td, bl, bd))
+    return 1;
+
+DEBG("dyn7 ");
+
+  /* free the decoding tables, return */
+  huft_free(tl);
+  huft_free(td);
+
+  DEBG(">");
+  return 0;
+}
+
+
+
+FUNC_STATIC int inflate_block(e)
+int *e;                 /* last block flag */
+/* decompress an inflated block */
+{
+  unsigned t;           /* block type */
+  register ulg b;       /* bit buffer */
+  register unsigned k;  /* number of bits in bit buffer */
+
+  DEBG("<blk");
+
+  /* make local bit buffer */
+  b = bb;
+  k = bk;
+
+
+  /* read in last block bit */
+  NEEDBITS(1)
+  *e = (int)b & 1;
+  DUMPBITS(1)
+
+
+  /* read in block type */
+  NEEDBITS(2)
+  t = (unsigned)b & 3;
+  DUMPBITS(2)
+
+
+  /* restore the global bit buffer */
+  bb = b;
+  bk = k;
+
+  /* inflate that block type */
+  if (t == 2)
+    return inflate_dynamic();
+  if (t == 0)
+    return inflate_stored();
+  if (t == 1)
+    return inflate_fixed();
+
+  DEBG(">");
+
+  /* bad block type */
+  return 2;
+}
+
+
+
+FUNC_STATIC int inflate()
+/* decompress an inflated entry */
+{
+  int e;                /* last block flag */
+  int r;                /* result code */
+  unsigned h;           /* maximum struct huft's malloc'ed */
+
+  /* initialize window, bit buffer */
+  wp = 0;
+  bk = 0;
+  bb = 0;
+
+
+  /* decompress until the last block */
+  h = 0;
+  do {
+    hufts = 0;
+    if ((r = inflate_block(&e)) != 0) {
+      return r;
+    }
+    if (hufts > h)
+      h = hufts;
+  } while (!e);
+
+  /* Undo too much lookahead. The next read will be byte aligned so we
+   * can discard unused bits in the last meaningful byte.
+   */
+  while (bk >= 8) {
+    bk -= 8;
+    inptr--;
+  }
+
+  /* flush out slide */
+  flush_output(wp);
+
+
+  /* return success */
+#ifdef INFLATE_DEBUG
+#ifdef EFI_COMPILE
+  Print(L"<%d> ", h);
+#else
+  printf("<%d> ", h);
+#endif
+#endif /* INFLATE_DEBUG */
+  return 0;
+}
+
+/**********************************************************************
+ *
+ * The following are support routines for inflate.c
+ *
+ **********************************************************************/
+
+static ulg crc_32_tab[256];
+static ulg crc;                /* initialized in makecrc() so it'll reside in bss */
+#define CRC_VALUE (crc ^ 0xffffffffUL)
+
+/*
+ * Code to compute the CRC-32 table. Borrowed from 
+ * gzip-1.0.3/makecrc.c.
+ */
+
+static void
+makecrc(void)
+{
+/* Not copyrighted 1990 Mark Adler     */
+
+  unsigned long c;      /* crc shift register */
+  unsigned long e;      /* polynomial exclusive-or pattern */
+  int i;                /* counter for all possible eight bit values */
+  int k;                /* byte being shifted into crc apparatus */
+
+  /* terms of polynomial defining this crc (except x^32): */
+  static const int p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};
+
+  /* Make exclusive-or pattern from polynomial */
+  e = 0;
+  for (i = 0; i < sizeof(p)/sizeof(int); i++)
+    e |= 1L << (31 - p[i]);
+
+  crc_32_tab[0] = 0;
+
+  for (i = 1; i < 256; i++)
+  {
+    c = 0;
+    for (k = i | 256; k != 1; k >>= 1)
+    {
+      c = c & 1 ? (c >> 1) ^ e : c >> 1;
+      if (k & 1)
+        c ^= e;
+    }
+    crc_32_tab[i] = c;
+  }
+
+  /* this is initialized here so this code could reside in ROM */
+  crc = (ulg)0xffffffffUL; /* shift register contents */
+}
+
+/*
+ * Do the uncompression!
+ */
+static int gunzip(void)
+{
+    uch flags;
+    unsigned char magic[2]; /* magic header */
+    char method;
+    ulg orig_crc = 0;       /* original crc */
+    ulg orig_len = 0;       /* original uncompressed length */
+    int res;
+
+    magic[0] = (unsigned char)get_byte();
+    magic[1] = (unsigned char)get_byte();
+    method = (unsigned char)get_byte();
+
+    if (magic[0] != 037 ||
+       ((magic[1] != 0213) && (magic[1] != 0236))) {
+           error("bad gzip magic numbers");
+           return -1;
+    }
+
+    /* We only support method #8, DEFLATED */
+    if (method != 8)  {
+           error("internal error, invalid method");
+           return -1;
+    }
+
+    flags  = (uch)get_byte();
+    if ((flags & ENCRYPTED) != 0) {
+           error("Input is encrypted\n");
+           return -1;
+    }
+    if ((flags & CONTINUATION) != 0) {
+           error("Multi part input\n");
+           return -1;
+    }
+    if ((flags & RESERVED) != 0) {
+           error("Input has invalid flags\n");
+           return -1;
+    }
+    (ulg)get_byte();   /* Get timestamp */
+    ((ulg)get_byte()) << 8;
+    ((ulg)get_byte()) << 16;
+    ((ulg)get_byte()) << 24;
+
+    (void)get_byte();  /* Ignore extra flags for the moment */
+    (void)get_byte();  /* Ignore OS type for the moment */
+
+    if ((flags & EXTRA_FIELD) != 0) {
+           unsigned len = (unsigned)get_byte();
+           len |= ((unsigned)get_byte())<<8;
+           while (len--) (void)get_byte();
+    }
+
+    /* Get original file name if it was truncated */
+    if ((flags & ORIG_NAME) != 0) {
+           /* Discard the old name */
+           while (get_byte() != 0) /* null */ ;
+    } 
+
+    /* Discard file comment if any */
+    if ((flags & COMMENT) != 0) {
+           while (get_byte() != 0) /* null */ ;
+    }
+
+    /* Decompress */
+    if ((res = inflate())) {
+           switch (res) {
+           case 0:
+                   break;
+           case 1:
+                   error("invalid compressed format (err=1)");
+                   break;
+           case 2:
+                   error("invalid compressed format (err=2)");
+                   break;
+           case 3:
+                   error("out of memory");
+                   break;
+           default:
+                   error("invalid compressed format (other)");
+           }
+           return -1;
+    }
+           
+    /* Get the crc and original length */
+    /* crc32  (see algorithm.doc)
+     * uncompressed input size modulo 2^32
+     */
+    orig_crc = (ulg) get_byte();
+    orig_crc |= (ulg) get_byte() << 8;
+    orig_crc |= (ulg) get_byte() << 16;
+    orig_crc |= (ulg) get_byte() << 24;
+    
+    orig_len = (ulg) get_byte();
+    orig_len |= (ulg) get_byte() << 8;
+    orig_len |= (ulg) get_byte() << 16;
+    orig_len |= (ulg) get_byte() << 24;
+    
+    /* Validate decompression */
+    if (orig_crc != CRC_VALUE) {
+           error("crc error");
+           return -1;
+    }
+    if (orig_len != bytes_out) {
+           error("length error");
+           return -1;
+    }
+    return 0;
+}
+
+
index 92b6f44008afe0692cb6a50dd03fa624ecc4fc91..09ed0f0eb8d2930fe552e8edf1935cc9f717b7be 100644 (file)
--- a/initrd.c
+++ b/initrd.c
@@ -29,7 +29,7 @@
 #include "elilo.h"
 
 /*
- * This function allocates memory for the initial ramdisk (initrd) and loads it to memory
+ * This function allocates memory for file image and loads it to memory
  * OUTPUTS:
  *     - ELILO_LOAD_SUCCESS: if everything works
  *     - ELILO_LOAD_ABORTED: in case the user decided to abort loading
  * Adapted from Bill Nottingham <notting@redhat.com>  patch for ELI.
  */
 INTN
-load_initrd(CHAR16 *filename, memdesc_t *initrd)
+load_file(CHAR16 *filename, memdesc_t *image)
 {
        EFI_STATUS status;
-       VOID *start_addr = initrd->start_addr;
-       UINT64 size = 0;
+       VOID *start_addr = image->start_addr;
        UINTN pgcnt;
+       UINT64 size = 0;
        fops_fd_t fd;
        INTN ret  = ELILO_LOAD_ERROR;
        
@@ -53,46 +53,48 @@ load_initrd(CHAR16 *filename, memdesc_t *initrd)
        /* Open the file */
        status = fops_open(filename, &fd);
        if (EFI_ERROR(status)) {
-               ERR_PRT((L"Open initrd file %s failed: %r", filename, status));
+               ERR_PRT((L"Open file %s failed: %r", filename, status));
                return -1;
        }
 
-       DBG_PRT((L"initrd_open %s worked", filename));
+       DBG_PRT((L"open %s worked", filename));
 
        /* warning: this function allocates memory  */
        status = fops_infosize(fd, &size);
        if (EFI_ERROR(status)) {
-               ERR_PRT((L"Couldn't read initrd file %s info %r",filename, status));
+               ERR_PRT((L"Couldn't read file %s info %r", filename, status));
                goto error;
        }
        
-       /* round up to get required number of pages (4KB) */
-       initrd->pgcnt = pgcnt = EFI_SIZE_TO_PAGES(size);
-
+       image->size = size;
 
+       /* round up to get required number of pages (4KB) */
+       image->pgcnt = pgcnt = EFI_SIZE_TO_PAGES(image->size);
 
        start_addr = alloc_pages(pgcnt, EfiLoaderData, start_addr ? AllocateAddress : AllocateAnyPages, start_addr);
        if (start_addr == NULL) {
-               ERR_PRT((L"Failed to allocate %d pages for initrd", pgcnt));
+               ERR_PRT((L"Failed to allocate %d pages for %s image", pgcnt,
+                        filename));
                goto error;
        }
-       VERB_PRT(2, Print(L"initrd: total_size: %ld bytes base: 0x%lx pages %d\n", 
-                       size, (UINT64)start_addr, pgcnt));
+       VERB_PRT(2, Print(L"%s image: total_size: %ld bytes base: 0x%lx "
+                         "pages %d\n", filename, image->size,
+                         (UINTN)start_addr, pgcnt));
 
-       Print(L"Loading initrd %s...", filename);
+       Print(L"Loading file %s...", filename);
 
-       ret = read_file(fd, size, start_addr);  
+       ret = read_file(fd, image->size, start_addr);   
 
        fops_close(fd);
 
        if (ret != ELILO_LOAD_SUCCESS) {
-               ERR_PRT((L"read initrd(%s) failed: %d", filename, ret));
+               ERR_PRT((L"read image(%s) failed: %d", filename, ret));
                goto error;
        }
 
        Print(L"done\n");
 
-       initrd->start_addr = start_addr;
+       image->start_addr = start_addr;
 
        return ELILO_LOAD_SUCCESS;
 
@@ -103,8 +105,9 @@ error:
         * make sure nothing is passed to kernel
         * in case of error.
         */
-       initrd->start_addr = 0;
-       initrd->pgcnt      = 0;
+       image->start_addr = 0;
+       image->pgcnt      = 0;
+       image->size       = 0;
 
        return ret;
 }