+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.
OPTIMFLAGS = -O2
DEBUGFLAGS = -Wall
CFLAGS = $(OPTIMFLAGS) -fpic -fshort-wchar $(DEBUGFLAGS)
-LDFLAGS = -nostdlib
+LDFLAGS = -nostdlib -znocombreloc
INSTALL = install
ifeq ($(CONFIG_machspec_netconfig),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 = /usr/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 = /usr/bin/
- CC = $(prefix)gcc
- 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
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 \
- 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
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 */
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",
* 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
* 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);
*/
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
{
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];
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");
}
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
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];
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));
* if no match is found, the args and initrd arguments may
* still be modified by global options in the config file.
*/
- ret = find_label((index < argc) ? argv[index] : NULL, 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 ((index < argc) && argv[index])
+ if ((index < argc) && argv[index])
StrCpy(kname, argv[index]);
else
StrCpy(kname, elilo_opt.default_kernel);
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) {
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;
elilo_opt.initrd[0] = CHAR_NULL;
goto 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 */
}
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);
# 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];
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));
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;
}
/*
* 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((index < argc) ? argv[index] : NULL, 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 ((index < argc) && argv[index])
+ if ((index < argc) && argv[index])
StrCpy(kname, argv[index]);
else
StrCpy(kname, elilo_opt.default_kernel);
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) {
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;
elilo_opt.initrd[0] = CHAR_NULL;
goto 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 */
}
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);
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];
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];
{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},
{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)},
}
EFI_STATUS
-read_config(CHAR16 *filename, INTN retry)
+read_config(CHAR16 *filename)
{
EFI_STATUS status;
INTN ret;
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
{
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);
}
}
}
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;
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;
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;
}
+elilo (3.6-1) unstable; urgency=low
+
+ * new upstream version
+
+ -- Bdale Garbee <bdale@gag.com> Mon, 9 Jan 2006 17:45:02 -0700
+
+elilo (3.4pre5.2-2) unstable; urgency=low
+
+ * change section from base to admin to match override
+ * accept patch to fix syntax issue in elilo script, closes: #342639
+
+ -- Bdale Garbee <bdale@gag.com> Fri, 9 Dec 2005 10:14:30 -0800
+
+elilo (3.4pre5.2-1) unstable; urgency=low
+
+ * new upstream version 3.5-pre2, closes: #338185
+ * implement suggestion from Thibaut Varene to have elilo.so try to modprobe
+ the efivars module before checking the environment for calling efibootmgr.
+ * update elilo.sh to always use relocatable on ia64 elilo.conf generation,
+ closes: #324067
+ * update debian/copyright to reflect upstream source move, closes: #341136
+
+ -- Bdale Garbee <bdale@gag.com> Thu, 8 Dec 2005 10:13:58 -0800
+
elilo (3.4-9) unstable; urgency=low
* patch from upstream to fix problems when wrong -C param is provided,
Source: elilo
-Section: base
+Section: admin
Priority: optional
Maintainer: Bdale Garbee <bdale@gag.com>
-Build-Depends: debhelper (>> 3.0.0), gnu-efi (>=3.0a-4)
-Standards-Version: 3.6.1.1
+Build-Depends: debhelper (>> 5), gnu-efi (>=3.0b-1)
+Standards-Version: 3.6.2.1
Package: elilo
Architecture: i386 ia64
This package was debianized by Bdale Garbee <bdale@gag.com> using sources
obtained from
- ftp://ftp.hpl.hp.com/pub/linux-ia64/
+ http://elilo.sourceforge.net/
Copyright:
- Copyright (C) 1999-2002 Hewlett-Packard Co.
+ Copyright (C) 1999-2003 Hewlett-Packard Co.
Contributed by David Mosberger <davidm@hpl.hp.com>.
Contributed by Stephane Eranian <eranian@hpl.hp.com>
EFIROOT=/EFI/debian
export LC_COLLATE=C
+ARCHITECTURE=$(dpkg --print-installation-architecture)
+
## catch signals, clean up junk in /tmp.
trap "cleanup" 0
trap "cleanup; exit 129" HUP
CONFERR=1
fi
+ # efibootmgr needs efivars, make sure kernel module is loaded
+ if modprobe -q efivars ; then
+ echo "Loaded efivars kernel module to enable use of efibootmgr"
+ fi
+
if [ ! -d /proc/efi/vars ] && [ ! -d /sys/firmware/efi/vars ] && [ "$efiboot" = 1 ] ; then
echo 1>&2 "$PRG: no efi/vars under /proc or /sys/firmware, boot menu not updated"
efiboot=0
default=$label
" > "$TMPCONF" || return 1
-if [ -d /proc/sgi_sn ]
+if [ "$ARCHITECTURE" = "ia64" ]
then
- # aha! This is an SGI Altix, and they need the relocatable option.
echo "relocatable" >> "$TMPCONF" || return 1
fi
# Uncomment this to turn on verbose mode.
#export DH_VERBOSE=1
-# This is the debhelper compatability version to use.
-export DH_COMPAT=3
-
configure: configure-stamp
configure-stamp:
dh_testdir
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.
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).
#include "elilo.h"
#include "vars.h"
+#include "gzip.h"
#include "getopt.h"
#include "fileops.h"
}
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;
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;
}
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;
}
UINTN cookie;
EFI_STATUS status = EFI_SUCCESS;
kdesc_t kd;
- memdesc_t imem;
+ memdesc_t imem, mmem;
INTN r;
/*
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:
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);
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");
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;
}
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);
/*
* 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);
+ 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
* 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
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 */
#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
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 */
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 */
typedef struct {
VOID *start_addr;
UINTN pgcnt;
+ UINTN size;
} memdesc_t;
typedef struct {
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);
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);
/*
*/
-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 *);
}
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)
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
*/
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);
/*
* 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 {
#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);
}
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;
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);
}
} 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;
+++ /dev/null
-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)
- }
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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__ */
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
--- /dev/null
+/*
+ * 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
+};
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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
+};
--- /dev/null
+/*
+ * 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
+};
#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];
/* 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()
/*
* Disable interrupts.
*/
-
asm volatile ( "cli" : : );
/*
*/
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
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.
*/
* Jump to kernel entry point.
*/
-
asm volatile ( "jmp *%%ecx" : : );
}
*/
/*
- * 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.
UINTN sizeof_init_gdt = sizeof init_gdt;
-
/*
* Highest available base memory address.
*
*
* 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.
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)
{
free_memmap(&md);
}
-/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*
* IA-32 specific boot parameters initialization routine
*/
boot_params_t *bp,
CHAR8 *cmdline,
memdesc_t *initrd,
+ memdesc_t *vmcode, /* no use for ia32 now*/
UINTN *cookie)
{
mmap_desc_t mdesc;
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;
}
* 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.
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
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.
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;
/*
* 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;
/*
* 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) \
; \
} \
}
-
{
UINTN test = 0;
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."));
if (EFI_ERROR(efi_status)) {
ERR_PRT((L"QueryMode failed. Fake it."));
-
mode = 3;
rows = 25;
cols = 80;
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;
free_kmem();
return -1;
}
-
*cookie = mdesc.cookie;
bp->s.efi_mem_map = (UINTN)mdesc.md;
bp->s.efi_mem_map_size = mdesc.map_size;
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;
}
#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))
#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
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,
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"));
/* 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
if (cnt > outcnt) cnt = outcnt;
Memcpy(dst, src, cnt);
+ if (cp->flags & CHUNK_FL_X)
+ flush_dcache (dst, cnt);
file_offset += cnt;
outcnt -= cnt;
+++ /dev/null
-/*
- * 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__ */
#include "loader.h"
#include "gzip.h"
+#define LD_NAME L"gzip_ia64"
+
static INTN
gzip_probe_format(CHAR16 *kname)
{
+++ /dev/null
-#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;
-}
-
-
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"));
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
extern INTN ia64_can_relocate();
+extern void flush_dcache (CHAR8 *addr, UINT64 len);
+
#endif /* __ELILO_PRIVATE_IA64_H__ */
/* __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
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 {
* 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;
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;
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));
+}
--- /dev/null
+#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;
+}
+
+
#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;
/* 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;
* 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;
}