diff --git a/ChangeLog b/ChangeLog index 55dad01..239ba95 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,11 +1,34 @@ +2005-12-01 Alex Williamson + * Applied patch from Fred Yang 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 + * 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 + * Increase the hardcoded size of the texmenu chooser menu from 16 to 64 +2004-09-23 Brett Johnson + * Fix for 924147. Thanks to Stephanie Schaaf for a patch + that the fix is based on. 2004-02-19 Brett Johnson - * 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. + * 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 * integrated ia32 compressed kernel support from Matt Tolentino - + 2003-08-20 Stephane Eranian * released 3.4 2003-08-19 Stephane Eranian @@ -93,7 +116,7 @@ * 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 * added a Linux utility program (elilovar in tools) to set/read/delete the EliloAlt EFI variable used to specify an alternate kernel to boot. diff --git a/Make.defaults b/Make.defaults index 48baaea..0a90776 100644 --- a/Make.defaults +++ b/Make.defaults @@ -95,38 +95,23 @@ ifeq ($(CONFIG_chooser_textmenu),y) CFLAGS += -DCONFIG_CHOOSER_TEXTMENU endif +prefix = /usr/bin/ + # Redhat 8.0 ia32 gcc-3.x version is reported to produce working EFI binaries. + # Redhat 9.0 ia32 gcc-3.x version is reported to produce BAD binaries. +CC = $(prefix)gcc +AS = $(prefix)as +LD = $(prefix)ld +AR = $(prefix)ar +RANLIB = $(prefix)ranlib +OBJCOPY = $(prefix)objcopy + ifeq ($(ARCH),ia64) - prefix = - prefix = /opt/gcc3.1/bin/ - CC = $(prefix)gcc - AS = $(prefix)as - LD = $(prefix)ld - LD = ld - AR = $(prefix)ar - RANLIB = $(prefix)ranlib - OBJCOPY = $(prefix)objcopy + GCC_VERSION=$(shell $(CROSS_COMPILE)$(CC) -v 2>&1 | fgrep 'gcc version' | cut -f3 -d' ' | cut -f1 -d'.') -GCC_VERSION=$(shell $(CROSS_COMPILE)$(CC) -v 2>&1 | fgrep 'gcc version' | cut -f3 -d' ' | cut -f1 -d'.') - -ifneq ($(GCC_VERSION),2) + ifneq ($(GCC_VERSION),2) CFLAGS += -frename-registers -endif -# -# EFI specs allows only lower floating point partition to be used -# -# Redhat 8.0 gcc-3.x version is reported to produce working EFI binaries. -# Redhat 9.0 gcc-3.x version is reported to produce BAD binaries. -# -CFLAGS += -mfixed-range=f32-f127 -else - ifeq ($(ARCH),ia32) - prefix = -# CC = $(prefix)gcc3 - 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 diff --git a/Makefile b/Makefile index d8ec67d..5015faf 100644 --- a/Makefile +++ b/Makefile @@ -61,7 +61,7 @@ endif FILES = elilo.o getopt.o strops.o loader.o \ fileops.o util.o vars.o alloc.o chooser.o \ config.o initrd.o alternate.o bootparams.o \ - fs/fs.o \ + gunzip.o fs/fs.o \ choosers/choosers.o \ devschemes/devschemes.o \ $(ARCH)/sysdeps.o \ diff --git a/alloc.c b/alloc.c index 373fbdc..349da9f 100644 --- a/alloc.c +++ b/alloc.c @@ -129,7 +129,7 @@ alloc_pages(UINTN pgcnt, EFI_MEMORY_TYPE type, EFI_ALLOCATE_TYPE where, VOID *ad status = BS->AllocatePages(where, type , pgcnt, &tmp); if (EFI_ERROR(status)) { - ERR_PRT((L"allocator: AllocatePages(%d, %d, %d, 0x%lx) failed (%r)\n", where, type, pgcnt, tmp, status)); + VERB_PRT(1, (L"allocator: AllocatePages(%d, %d, %d, 0x%lx) failed (%r)\n", where, type, pgcnt, tmp, status)); return NULL; } /* XXX: will cause warning on IA-32 */ @@ -155,7 +155,7 @@ free(VOID *addr) if (p->addr == addr) goto found; } /* not found */ - ERR_PRT((L"allocator: invalid free @ 0x%lx\n", addr)); + VERB_PRT(1, (L"allocator: invalid free @ 0x%lx\n", addr)); return; found: DBG_PRT((L"free: %s @0x%lx size=%ld\n", diff --git a/bootparams.c b/bootparams.c index a6c9d7c..8859fcc 100644 --- a/bootparams.c +++ b/bootparams.c @@ -38,7 +38,7 @@ * bp : the address of the bootparams otherwise (opaque type) */ VOID * -create_boot_params(CHAR16 *args, memdesc_t *initrd, UINTN *cookie) +create_boot_params(CHAR16 *args, memdesc_t *initrd, memdesc_t *vmcode, UINTN *cookie) { /* * XXX: need cleanup @@ -69,6 +69,7 @@ create_boot_params(CHAR16 *args, memdesc_t *initrd, UINTN *cookie) * Allocate memory for boot parameters. * This CANNOT be EfiLoaderData or EfiLoaderCode as the kernel * frees this region when initializing. + * FIXME: Is this a bug? (since the memory type *is* EfiLoaderData) */ bp = (boot_params_t *)alloc(BOOT_PARAM_MEMSIZE, EfiLoaderData); @@ -95,7 +96,7 @@ create_boot_params(CHAR16 *args, memdesc_t *initrd, UINTN *cookie) */ Memset(bp, 0, BOOT_PARAM_MEMSIZE); - if (sysdeps_create_boot_params(bp, cp, initrd, cookie) == -1) return 0; + if (sysdeps_create_boot_params(bp, cp, initrd, vmcode, cookie) == -1) return 0; /* * Convert kernel command line args from UNICODE to ASCII and put them where diff --git a/choosers/simple.c b/choosers/simple.c index 0af1fa7..b246a91 100644 --- a/choosers/simple.c +++ b/choosers/simple.c @@ -37,6 +37,7 @@ display_label_info(CHAR16 *name) { CHAR16 *desc; CHAR16 initrd_name[CMDLINE_MAXLEN]; + CHAR16 vmcode_name[CMDLINE_MAXLEN]; CHAR16 options_tmp[CMDLINE_MAXLEN]; CHAR16 options[CMDLINE_MAXLEN]; CHAR16 kname[FILENAME_MAXLEN]; @@ -46,9 +47,9 @@ display_label_info(CHAR16 *name) Print(L"desc : %s\n", desc); } - initrd_name[0] = options_tmp[0] = kname[0] = CHAR_NULL; + initrd_name[0] = vmcode_name[0] = options_tmp[0] = kname[0] = CHAR_NULL; - if (find_label(name, kname, options_tmp, initrd_name) == -1) { + if (find_label(name, kname, options_tmp, initrd_name, vmcode_name) == -1) { StrCpy(kname, name); Print(L"\n"); } @@ -56,6 +57,7 @@ display_label_info(CHAR16 *name) Print(L"cmdline: %s %s\n", kname, options); if (initrd_name[0]) Print(L"initrd : %s\n", initrd_name); + if (vmcode_name[0]) Print(L"vmcode : %s\n", vmcode_name); } static VOID @@ -247,6 +249,7 @@ simple_choose(CHAR16 **argv, INTN argc, INTN index, CHAR16 *kname, CHAR16 *cmdli CHAR16 buffer[CMDLINE_MAXLEN]; CHAR16 alt_buffer[CMDLINE_MAXLEN]; CHAR16 initrd_name[CMDLINE_MAXLEN]; + CHAR16 vmcode_name[CMDLINE_MAXLEN]; CHAR16 args[CMDLINE_MAXLEN]; CHAR16 devname[CMDLINE_MAXLEN]; CHAR16 dpath[FILENAME_MAXLEN]; @@ -259,7 +262,7 @@ simple_choose(CHAR16 **argv, INTN argc, INTN index, CHAR16 *kname, CHAR16 *cmdli display_message(); restart: - initrd_name[0] = kname[0] = cmdline[0] = args[0] = CHAR_NULL; + initrd_name[0] = vmcode_name[0] = kname[0] = cmdline[0] = args[0] = CHAR_NULL; /* reset per image loader options */ Memset(&elilo_opt.img_opt, 0, sizeof(elilo_opt.img_opt)); @@ -303,14 +306,14 @@ restart: * if no match is found, the args and initrd arguments may * still be modified by global options in the config file. */ - ret = find_label(argv[index], kname, args, initrd_name); + ret = find_label((index < argc) ? argv[index] : NULL, kname, args, initrd_name, vmcode_name); /* * not found, so assume first argument is kernel name and * not label name */ if (ret == -1) { - if (argv[index]) + if ((index < argc) && argv[index]) StrCpy(kname, argv[index]); else StrCpy(kname, elilo_opt.default_kernel); @@ -335,9 +338,14 @@ restart: StrCpy(elilo_opt.initrd, initrd_name); } + if (elilo_opt.vmcode[0] == CHAR_NULL && vmcode_name[0] != CHAR_NULL) { + StrCpy(elilo_opt.vmcode, vmcode_name); + } + VERB_PRT(1, { Print(L"kernel is '%s'\n", kname); Print(L"arguments are '%s'\n", args); if (elilo_opt.initrd[0]) Print(L"initrd is '%s'\n", elilo_opt.initrd); + if (elilo_opt.vmcode[0]) Print(L"vmm is '%s'\n", elilo_opt.vmcode); }); if (elilo_opt.prompt == 0) { @@ -379,7 +387,8 @@ restart: */ len = StrLen(BOOT_IMG_STR) /* BOOT_IMAGE= */ +StrLen(devname) /* device name */ - +StrLen(kname) /* kernel name */ + /* kernel name */ + +elilo_opt.vmcode[0] ? StrLen(elilo_opt.vmcode) : StrLen(kname) +1 /* space */ +StrLen(args); /* args length */ @@ -389,7 +398,10 @@ restart: } StrCpy(cmdline, L"BOOT_IMAGE="); StrCat(cmdline, devname); - StrCat(cmdline, kname); + if (elilo_opt.vmcode[0]) + StrCat(cmdline, elilo_opt.vmcode); + else + StrCat(cmdline, kname); StrCat(cmdline, L" "); StrCat(cmdline, args); diff --git a/choosers/textmenu.c b/choosers/textmenu.c index aaf2a4b..f64784e 100644 --- a/choosers/textmenu.c +++ b/choosers/textmenu.c @@ -28,7 +28,7 @@ #include "elilo.h" -#define MAX_LABELS 16 +#define MAX_LABELS 64 #define MSGBUFLEN 4096 static UINT8 msgbuf[MSGBUFLEN]; @@ -358,6 +358,7 @@ textmenu_choose(CHAR16 **argv, INTN argc, INTN index, CHAR16 *kname, CHAR16 *cmd # define BOOT_IMG_STR L"BOOT_IMAGE=" CHAR16 label[CMDLINE_MAXLEN]; CHAR16 initrd_name[CMDLINE_MAXLEN]; + CHAR16 vmcode_name[CMDLINE_MAXLEN]; CHAR16 args[CMDLINE_MAXLEN]; CHAR16 devname[CMDLINE_MAXLEN]; CHAR16 dpath[FILENAME_MAXLEN]; @@ -412,16 +413,16 @@ restart: * still be modified by global options in the config file. */ if (label[0]) - ret = find_label(label, kname, args, initrd_name); + ret = find_label(label, kname, args, initrd_name, vmcode_name); else - ret = find_label(argv[index], kname, args, initrd_name); + ret = find_label((index < argc) ? argv[index] : NULL, kname, args, initrd_name, vmcode_name); /* * not found, so assume first argument is kernel name and * not label name */ if (ret == -1) { - if (argv[index]) + if ((index < argc) && argv[index]) StrCpy(kname, argv[index]); else StrCpy(kname, elilo_opt.default_kernel); @@ -448,9 +449,14 @@ restart: StrCpy(elilo_opt.initrd, initrd_name); } + if (elilo_opt.vmcode[0] == CHAR_NULL && vmcode_name[0] != CHAR_NULL) { + StrCpy(elilo_opt.vmcode, vmcode_name); + } + VERB_PRT(1, { Print(L"kernel is '%s'\n", kname); Print(L"arguments are '%s'\n", args); if (elilo_opt.initrd[0]) Print(L"initrd is '%s'\n", elilo_opt.initrd); + if (elilo_opt.vmcode[0]) Print(L"vmm is '%s'\n", elilo_opt.vmcode); }); if (elilo_opt.prompt == 0) { @@ -494,6 +500,7 @@ restart: len = StrLen(BOOT_IMG_STR) /* BOOT_IMAGE= */ +StrLen(devname) /* device name */ +StrLen(kname) /* kernel name */ + +elilo_opt.vmcode[0] ? StrLen(elilo_opt.vmcode) : StrLen(kname) +1 /* space */ +StrLen(args); /* args length */ @@ -505,7 +512,10 @@ restart: } StrCpy(cmdline, L"BOOT_IMAGE="); StrCat(cmdline, devname); - StrCat(cmdline, kname); + if (elilo_opt.vmcode[0]) + StrCat(cmdline, elilo_opt.vmcode); + else + StrCat(cmdline, kname); StrCat(cmdline, L" "); StrCat(cmdline, args); diff --git a/config.c b/config.c index c556484..e24c0c0 100644 --- a/config.c +++ b/config.c @@ -68,6 +68,7 @@ typedef struct boot_image { CHAR16 kname[FILENAME_MAXLEN]; CHAR16 options[MAX_STRING]; CHAR16 initrd[FILENAME_MAXLEN]; + CHAR16 vmcode[FILENAME_MAXLEN]; CHAR16 root[FILENAME_MAXLEN]; CHAR16 fallback[MAX_STRING]; CHAR16 description[MAX_STRING]; @@ -93,6 +94,7 @@ typedef enum { typedef struct { CHAR16 root[FILENAME_MAXLEN]; /* globally defined root fs */ CHAR16 initrd[FILENAME_MAXLEN];/* globally defined initrd */ + CHAR16 vmcode[FILENAME_MAXLEN];/* globally defined boot-time module */ CHAR16 options[MAX_STRING]; CHAR16 default_image_name[MAX_STRING]; CHAR16 message_file[MAX_MESSAGES][FILENAME_MAXLEN]; @@ -144,6 +146,7 @@ static config_option_t global_common_options[]={ {OPT_BOOL, OPT_GLOBAL, L"noedd30", NULL, NULL, &global_config.edd30_no_force}, {OPT_CMD, OPT_GLOBAL, L"append", NULL, NULL, global_config.options}, {OPT_FILE, OPT_GLOBAL, L"initrd", NULL, NULL, global_config.initrd}, +{OPT_FILE, OPT_GLOBAL, L"vmm", NULL, NULL, global_config.vmcode}, {OPT_FILE, OPT_GLOBAL, L"image", do_image, NULL, opt_offsetof(kname)}, {OPT_BOOL, OPT_GLOBAL, L"checkalt", NULL, NULL, &global_config.alt_check}, {OPT_STR, OPT_GLOBAL, L"chooser", NULL, check_chooser, global_config.chooser}, @@ -168,6 +171,7 @@ static config_option_t image_common_options[]={ {OPT_CMD, OPT_IMAGE, L"append", do_options, NULL, opt_offsetof(options)}, {OPT_CMD, OPT_IMAGE, L"literal", do_literal, NULL, NULL}, {OPT_FILE, OPT_IMAGE, L"initrd", NULL, NULL, opt_offsetof(initrd)}, + {OPT_FILE, OPT_IMAGE, L"vmm", NULL, NULL, opt_offsetof(vmcode)}, {OPT_STR, OPT_IMAGE, L"label", NULL, NULL, opt_offsetof(label)}, {OPT_FILE, OPT_IMAGE, L"image", do_image, NULL, opt_offsetof(kname)}, {OPT_STR, OPT_IMAGE, L"description", NULL, NULL, opt_offsetof(description)}, @@ -882,10 +886,10 @@ print_label_list(VOID) { boot_image_t *img, *dfl = global_config.default_image; - if (dfl) Print(L"%s ", dfl->label); + if (dfl) Print(L"\t%s\n", dfl->label); for (img = image_list; img; img = img->next) { - if (img != dfl) Print(L"%s ", img->label); + if (img != dfl) Print(L"\t%s\n", img->label); } } @@ -933,7 +937,7 @@ find_description(CHAR16 *label) } INTN -find_label(CHAR16 *label, CHAR16 *kname, CHAR16 *options, CHAR16 *initrd) +find_label(CHAR16 *label, CHAR16 *kname, CHAR16 *options, CHAR16 *initrd, CHAR16 *vmcode) { boot_image_t *img; @@ -966,6 +970,7 @@ find_label(CHAR16 *label, CHAR16 *kname, CHAR16 *options, CHAR16 *initrd) if (global_config.readonly) StrCat(options, L" ro"); if (global_config.initrd[0]) StrCpy(initrd, global_config.initrd); + if (global_config.vmcode[0]) StrCpy(vmcode, global_config.vmcode); /* make sure we don't get garbage here */ elilo_opt.sys_img_opts = NULL; @@ -1003,12 +1008,17 @@ found: else if (global_config.initrd[0]) StrCpy(initrd, global_config.initrd); + if (img->vmcode[0]) + StrCpy(vmcode, img->vmcode); + else if (global_config.vmcode[0]) + StrCpy(vmcode, global_config.vmcode); + /* * point to architecture dependent options for this image */ elilo_opt.sys_img_opts = &img->sys_img_opts; - DBG_PRT((L"label %s: kname=%s options=%s initrd=%s", img->label, kname, options, initrd)); + DBG_PRT((L"label %s: kname=%s options=%s initrd=%s vmcode=%s", img->label, kname, options, initrd, vmcode)); return 0; } diff --git a/elilo-ia32.efi b/elilo-ia32.efi deleted file mode 100644 index b2ca1c8..0000000 Binary files a/elilo-ia32.efi and /dev/null differ diff --git a/elilo-ia64.efi b/elilo-ia64.efi index 9022ad4..6404430 100644 Binary files a/elilo-ia64.efi and b/elilo-ia64.efi differ diff --git a/elilo.c b/elilo.c index 19731c9..6bdd6bd 100644 --- a/elilo.c +++ b/elilo.c @@ -34,6 +34,7 @@ #include "elilo.h" #include "vars.h" +#include "gzip.h" #include "getopt.h" #include "fileops.h" @@ -84,13 +85,23 @@ do_kernel_load(CHAR16 *kname, kdesc_t *kd) } INTN -kernel_load(EFI_HANDLE image, CHAR16 *kname, kdesc_t *kd, memdesc_t *imem) +kernel_load(EFI_HANDLE image, CHAR16 *kname, kdesc_t *kd, memdesc_t *imem, memdesc_t *mmem) { + CHAR16 kernel[CMDLINE_MAXLEN]; + /* + * Do the vm image switch here + * if there is "vmm=" then elilo should load image specified + * in "vmm=" and then give the "image" to vmm as target kernel image + */ + if (elilo_opt.vmcode[0]) + StrCpy(kernel, elilo_opt.vmcode); + else + StrCpy(kernel, kname); /* * Now let's try to load the kernel ! */ - switch(do_kernel_load(kname, kd)) { + switch(do_kernel_load(kernel, kd)) { case ELILO_LOAD_SUCCESS: break; @@ -101,6 +112,7 @@ kernel_load(EFI_HANDLE image, CHAR16 *kname, kdesc_t *kd, memdesc_t *imem) case ELILO_LOAD_ABORTED: /* we drop initrd in case we aborted the load */ elilo_opt.initrd[0] = CHAR_NULL; + elilo_opt.vmcode[0] = CHAR_NULL; /* will go back to interactive selection */ elilo_opt.prompt = 1; @@ -111,22 +123,22 @@ kernel_load(EFI_HANDLE image, CHAR16 *kname, kdesc_t *kd, memdesc_t *imem) } VERB_PRT(3, Print(L"kernel loaded in [0x%lx-0x%lx] entry=0x%lx\n", - (UINT64)kd->kstart, (UINT64)kd->kend, (UINT64)kd->kentry)); + (unsigned long)kd->kstart, (unsigned long)kd->kend, (unsigned long)kd->kentry)); if (elilo_opt.initrd[0]) { if (sysdeps_initrd_get_addr(kd, imem) == -1) goto exit_error; - switch(load_initrd(elilo_opt.initrd, imem)) { + switch(load_file(elilo_opt.initrd, imem)) { case ELILO_LOAD_SUCCESS: break; case ELILO_LOAD_ERROR: goto exit_error; case ELILO_LOAD_ABORTED: - /* the free_kmem() is the responsibility of the loader */ - + free_kmem(); /* we drop initrd in case we aborted the load */ elilo_opt.initrd[0] = CHAR_NULL; + elilo_opt.vmcode[0] = CHAR_NULL; elilo_opt.prompt = 1; elilo_opt.timeout = ELILO_DEFAULT_TIMEOUT; elilo_opt.delay = 0; @@ -134,10 +146,52 @@ kernel_load(EFI_HANDLE image, CHAR16 *kname, kdesc_t *kd, memdesc_t *imem) return ELILO_LOAD_RETRY; } } + + if (elilo_opt.vmcode[0]) { + + mmem->start_addr = 0; /* let the allocator decide */ + + switch(load_file(kname, mmem)) { + case ELILO_LOAD_SUCCESS: + break; + case ELILO_LOAD_ERROR: + goto exit_error; + case ELILO_LOAD_ABORTED: + if (imem->start_addr) + free(imem->start_addr); + free_kmem(); + /* we drop initrd in case we aborted the load */ + elilo_opt.initrd[0] = CHAR_NULL; + elilo_opt.vmcode[0] = CHAR_NULL; + elilo_opt.prompt = 1; + elilo_opt.timeout = ELILO_DEFAULT_TIMEOUT; + elilo_opt.delay = 0; + + return ELILO_LOAD_RETRY; + } + + /* Test for a compressed image and unzip if found */ + if (gzip_probe(mmem->start_addr, mmem->size) == 0 && + gunzip_image(mmem) != ELILO_LOAD_SUCCESS) { + if (imem->start_addr) + free(imem->start_addr); + free(mmem->start_addr); + free_kmem(); + /* we drop initrd in case we aborted the load */ + elilo_opt.initrd[0] = CHAR_NULL; + elilo_opt.vmcode[0] = CHAR_NULL; + elilo_opt.prompt = 1; + elilo_opt.timeout = ELILO_DEFAULT_TIMEOUT; + elilo_opt.delay = 0; + + return ELILO_LOAD_RETRY; + } + } return ELILO_LOAD_SUCCESS; exit_error: free_kmem(); if (imem->start_addr) free(imem->start_addr); + if (mmem->start_addr) free(mmem->start_addr); return ELILO_LOAD_ERROR; } @@ -152,7 +206,7 @@ main_loop(EFI_HANDLE dev, CHAR16 **argv, INTN argc, INTN index, EFI_HANDLE image UINTN cookie; EFI_STATUS status = EFI_SUCCESS; kdesc_t kd; - memdesc_t imem; + memdesc_t imem, mmem; INTN r; /* @@ -164,12 +218,12 @@ main_loop(EFI_HANDLE dev, CHAR16 **argv, INTN argc, INTN index, EFI_HANDLE image for(;;) { kname[0] = cmdline_tmp[0] = cmdline[0] = CHAR_NULL; - imem.start_addr = 0; imem.pgcnt = 0; + imem.start_addr = 0; imem.pgcnt = 0; imem.size = 0; elilo_opt.sys_img_opts = NULL; if (kernel_chooser(argv, argc, index, kname, cmdline_tmp) == -1) goto exit_error; - switch (kernel_load(image, kname, &kd, &imem)) { + switch (kernel_load(image, kname, &kd, &imem, &mmem)) { case ELILO_LOAD_SUCCESS: goto do_launch; case ELILO_LOAD_ERROR: @@ -187,7 +241,7 @@ do_launch: close_devices(); /* No console output permitted after create_boot_params()! */ - if ((bp=create_boot_params(cmdline, &imem, &cookie)) == 0) goto error; + if ((bp=create_boot_params(cmdline, &imem, &mmem, &cookie)) == 0) goto error; /* terminate bootservices */ status = BS->ExitBootServices(image, cookie); @@ -221,6 +275,7 @@ elilo_help(VOID) Print(L"-v verbose level(can appear multiple times)\n"); Print(L"-a always check for alternate kernel image\n"); Print(L"-i file load file as the initial ramdisk\n"); + Print(L"-m file load file as additional boot time vmm module\n"); Print(L"-C file indicate the config file to use\n"); Print(L"-P parse config file only (verify syntax)\n"); Print(L"-D enable debug prints\n"); @@ -491,6 +546,13 @@ efi_main (EFI_HANDLE image, EFI_SYSTEM_TABLE *system_tab) } StrCpy(elilo_opt.initrd, Optarg); break; + case 'm': + if (StrLen(Optarg) >= FILENAME_MAXLEN-1) { + Print(L"vmm module filename is limited to %d characters\n", FILENAME_MAXLEN); + goto do_exit; + } + StrCpy(elilo_opt.vmcode, Optarg); + break; case 'C': if (StrLen(Optarg) >= FILENAME_MAXLEN-1) { Print(L"config filename is limited to %d characters\n", FILENAME_MAXLEN); @@ -607,11 +669,19 @@ efi_main (EFI_HANDLE image, EFI_SYSTEM_TABLE *system_tab) * if there was an error when parsing the config file, then * we force interactive mode to give a chance to the user. * We also clear the error. - */ - if (ret && argc == 1) { - Print(L"forcing interactive mode because of errors\n"); + */ + if (ret != EFI_SUCCESS) { + Print(L"forcing interactive mode due to config file error(s)\n"); elilo_opt.prompt = 1; } + /* + * However, if the user specified a kernel on the command line + * then we don't go to interactive mode, even if there was an option in + * the config file telling us to do so. + */ + if (argc > Optind) { + elilo_opt.prompt = 0; + } /* * If EDD30 EFI variable was not set to TRUE (or not defined), we @@ -627,13 +697,6 @@ efi_main (EFI_HANDLE image, EFI_SYSTEM_TABLE *system_tab) ret = EFI_LOAD_ERROR; - /* - * if the user specified a kernel on the command line - * then we don't go to interactive mode even if it - * was set in the config file or set because of an - * error parsing the config file. - */ - if (argc > Optind) elilo_opt.prompt = 0; /* set default timeout if going interactive */ diff --git a/elilo.h b/elilo.h index 7f0d768..74f740d 100644 --- a/elilo.h +++ b/elilo.h @@ -81,6 +81,7 @@ typedef struct { UINTN delay; /* delay before booting the image */ UINTN verbose; /* verbosity level [1-5] */ CHAR16 initrd[FILENAME_MAXLEN]; /* name of file for initial ramdisk */ + CHAR16 vmcode[FILENAME_MAXLEN]; /* name of file for boot time module*/ UINT8 delay_set; /* mark whether or not delay was specified on cmdline */ UINT8 edd30_on; /* true is EDD30 variable is TRUE */ UINT8 edd30_no_force; /* don't force EDD30 variable to true */ @@ -112,6 +113,7 @@ extern EFI_SYSTEM_TABLE *systab; typedef struct { VOID *start_addr; UINTN pgcnt; + UINTN size; } memdesc_t; typedef struct { @@ -169,7 +171,7 @@ extern VOID U2ascii(CHAR16 *, CHAR8 *, UINTN); /* from config.c (more in config.h) */ 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); @@ -178,13 +180,13 @@ extern VOID *get_next_description(VOID *prev, CHAR16 **label, CHAR16 **descripti extern CHAR16 *get_config_file(VOID); /* from initrd.c */ -extern INTN load_initrd(CHAR16 *, memdesc_t *); +extern INTN load_file(CHAR16 *, memdesc_t *); /* from alternate.c */ extern INTN alternate_kernel(CHAR16 *, INTN); /* from bootparams.c */ -extern VOID *create_boot_params (CHAR16 *, memdesc_t *, UINTN *); +extern VOID *create_boot_params (CHAR16 *, memdesc_t *, memdesc_t *, UINTN *); extern VOID free_boot_params(VOID *bp); /* @@ -192,7 +194,7 @@ extern VOID free_boot_params(VOID *bp); */ -extern INTN sysdeps_create_boot_params(boot_params_t *, CHAR8 *, memdesc_t *, UINTN *); +extern INTN sysdeps_create_boot_params(boot_params_t *, CHAR8 *, memdesc_t *, memdesc_t *, UINTN *); extern VOID sysdeps_free_boot_params(boot_params_t *); extern INTN sysdeps_init(EFI_HANDLE dev); extern INTN sysdeps_initrd_get_addr(kdesc_t *, memdesc_t *); diff --git a/fileops.c b/fileops.c index 1678f0f..85f3485 100644 --- a/fileops.c +++ b/fileops.c @@ -391,22 +391,22 @@ fops_setdefaults(struct config_file *defconf, CHAR16 *kname, UINTN maxlen, CHAR1 boot_dev->fops->setdefaults(boot_dev->fops->intf, defconf, kname, maxlen, devpath); } i=0; while (i= MAX_DEFAULT_CONFIGS) { Print(L"ERROR: i = %d, MAX_DEFAULT_CONFIGS is not large enough\n", i); return EFI_INVALID_PARAMETER; } -//#endif +#endif StrnCpy(defconf[i].fname, FILEOPS_ARCH_DEFAULT_CONFIG, maxlen-1); StrnCpy(defconf[i+1].fname, FILEOPS_DEFAULT_CONFIG, maxlen-1); -//#ifdef ELILO_DEBUG +#ifdef ELILO_DEBUG VERB_PRT(3,Print(L"Default config filename list:\n")); for (i=0; i + * + * Copyright (C) 2001-2003 Hewlett-Packard Co. + * Contributed by Stephane Eranian + * + * Copyright (C) 2001 Silicon Graphics, Inc. + * Contributed by Brent Casavant + * + * 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 +#include + +#include "elilo.h" + +#include "gzip.h" + +#define LD_NAME L"gunzip" + +#define memzero(s, n) Memset((VOID *)(s), 0, (n)) +#define memcpy(a,b,n) Memcpy((VOID *)(a),(b),(n)) + +/* size of output buffer */ +#define WSIZE 0x8000 /* Window size must be at least 32k, */ + /* and a power of two */ +/* + * gzip declarations + */ +#define OF(args) args +#define FUNC_STATIC static + +typedef unsigned char uch; +typedef unsigned short ush; +typedef unsigned long ulg; + +/* + * static parameters to gzip helper functions + * we cannot use paramters because API was not + * designed that way + */ +static uch *inbuf; /* input buffer (compressed data) */ +static uch *window; /* output buffer (uncompressed data) */ + +static VOID *outbuf; +unsigned char *outptr; +static unsigned long outsize; + +static unsigned inptr = 0; /* index of next byte to be processed in inbuf */ +static unsigned outcnt = 0; /* bytes in output buffer */ + +#define get_byte() inbuf[inptr++] + +/* Diagnostic functions */ +#ifdef INFLATE_DEBUG +# define Assert(cond,msg) {if(!(cond)) error(msg);} +int stderr; +# define Trace(x) Print(L"line %d:\n", __LINE__); +# define Tracev(x) {if (verbose) Print(L"line %d:\n", __LINE__) ;} +# define Tracevv(x) {if (verbose>1) Print(L"line %d:\n", __LINE__) ;} +# define Tracec(c,x) {if (verbose && (c)) Print(L"line %d:\n", __LINE__) ;} +# define Tracecv(c,x) {if (verbose>1 && (c)) Print(L"line %d:\n", __LINE__) ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + +static void flush_window(void); +static void error(char *m); +static long bytes_out; + +static void error(char *m); + +#define gzip_malloc(size) (void *)alloc(size, 0) +#define gzip_free(where) free(where) + +#include "inflate.c" + +/* + * Run a set of bytes through the crc shift register. If s is a NULL + * pointer, then initialize the crc shift register contents instead. + * Return the current crc in either case. + * + * Input: + * S pointer to bytes to pump through. + * N number of bytes in S[]. + */ +static void +updcrc(unsigned char *s, unsigned n) +{ + register unsigned long c; + /* crc is defined in inflate.c */ + + c = crc; + while (n--) { + c = crc_32_tab[((int)c ^ (*s++)) & 0xff] ^ (c >> 8); + } + crc = c; + return; +} + +/* + * Clear input and output buffers + */ +static void +clear_bufs(void) +{ + outcnt = 0; + inptr = 0; +} + +/* + * Write the output window window[0..outcnt-1] holding uncompressed + * data and update crc. + */ +void +flush_window(void) +{ + /* + * We'll end up relying on the CRC check and size check failing + * if there's actually more data than we expect. + */ + if (!outcnt || bytes_out + outcnt > outsize) + return; + + updcrc(window, outcnt); + + Memcpy(outptr, window, outcnt); + outptr += outcnt; + bytes_out += outcnt; + + outcnt = 0; +} + +static void +error(char *x) +{ + ERR_PRT((L"%s : %a", LD_NAME, x)); + /* will eventually exit with error from gunzip() */ +} + +static INT32 +decompress(VOID) +{ + INT32 ret; + + clear_bufs(); + makecrc(); + Print(L"Uncompressing... "); + ret = gunzip(); + if (ret == 0) Print(L"done\n"); + return ret == 0 ? 0 : -1; +} + +int +gunzip_image(memdesc_t *image) +{ + UINTN pgcnt; + + inbuf = image->start_addr; + + /* + * Last 4 bytes of gzip'd image indicates the uncompressed size + */ + outsize = inbuf[image->size - 1] << 24 | inbuf[image->size - 2] << 16 | + inbuf[image->size - 3] << 8 | inbuf[image->size - 4]; + + pgcnt = EFI_SIZE_TO_PAGES(outsize); + + outbuf = alloc_pages(pgcnt, EfiLoaderData, AllocateAnyPages, 0); + if (outbuf == NULL) { + ERR_PRT((L"%s : allocate output buffer failed\n", LD_NAME)); + return -1; + } + outptr = outbuf; + + window = (void *)alloc(WSIZE, 0); + if (window == NULL) { + ERR_PRT((L"%s : allocate output window failed\n", LD_NAME)); + free(outbuf); + return -1; + } + + bytes_out = 0; + + if (decompress() != 0) { + free(window); + free(outbuf); + return ELILO_LOAD_ERROR; + } + + free(window); + free(image->start_addr); + + image->start_addr = outbuf; + image->size = outsize; + image->pgcnt = pgcnt; + + return ELILO_LOAD_SUCCESS; +} diff --git a/ia64/gzip.h b/gzip.h similarity index 50% rename from ia64/gzip.h rename to gzip.h index 69749df..88b53f6 100644 --- a/ia64/gzip.h +++ b/gzip.h @@ -26,10 +26,42 @@ #ifndef __GZIP_H__ #define __GZIP_H__ - -int gzip_probe(unsigned char *, unsigned long); +int gunzip_image(memdesc_t *); int gunzip_kernel(fops_fd_t, kdesc_t *); -#define LD_NAME L"gzip_ia64" +/* 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__ */ diff --git a/ia32/gzip.c b/ia32/gzip.c index fdd7284..fff5f6d 100644 --- a/ia32/gzip.c +++ b/ia32/gzip.c @@ -34,6 +34,8 @@ #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)) diff --git a/ia32/gzip.h b/ia32/gzip.h deleted file mode 100644 index 296bf3c..0000000 --- a/ia32/gzip.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) 2001-2002 Hewlett-Packard Co. - * Contributed by Stephane Eranian - * - * 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_ia32" - -#endif /* __GZIP_H__ */ diff --git a/ia32/gzip_loader.c b/ia32/gzip_loader.c index 687b301..2e11b84 100644 --- a/ia32/gzip_loader.c +++ b/ia32/gzip_loader.c @@ -30,6 +30,8 @@ #include "loader.h" #include "gzip.h" +#define LD_NAME L"gzip_ia32" + static INTN gzip_probe_format(CHAR16 *kname) { diff --git a/ia32/inflate.c b/ia32/inflate.c deleted file mode 100644 index 5532250..0000000 --- a/ia32/inflate.c +++ /dev/null @@ -1,1205 +0,0 @@ -#define DEBG(x) -#define DEBG1(x) -/* inflate.c -- Not copyrighted 1992 by Mark Adler - version c10p1, 10 January 1993 */ - -/* - * Adapted for booting Linux by Hannu Savolainen 1993 - * based on gzip-1.0.3 - * - * Nicolas Pitre , 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 -# include -#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())<>=(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(""); - 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(" 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(" 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(""); - - /* 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) -{ - /* FIXME this is wrong here! FIXME!!!!*/ - 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; -} - - diff --git a/ia32/system.c b/ia32/system.c index 7c2228a..1dbbc58 100644 --- a/ia32/system.c +++ b/ia32/system.c @@ -164,6 +164,7 @@ sysdeps_create_boot_params( boot_params_t *bp, CHAR8 *cmdline, memdesc_t *initrd, + memdesc_t *vmcode, /* no use for ia32 now*/ UINTN *cookie) { mmap_desc_t mdesc; @@ -270,7 +271,7 @@ sysdeps_create_boot_params( if (initrd->start_addr && initrd->pgcnt) { /* %%TBD - This will probably have to be changed. */ bp->s.initrd_start = (UINT32)initrd->start_addr; - bp->s.initrd_size = (UINT32)(initrd->pgcnt * EFI_PAGE_SIZE); + bp->s.initrd_size = (UINT32)(initrd->size); /* * This is the RAMdisk root device for RedHat 2.2.x diff --git a/ia64/gzip.c b/ia64/gzip.c index bb5a065..01e28c8 100644 --- a/ia64/gzip.c +++ b/ia64/gzip.c @@ -37,6 +37,8 @@ #include "private.h" #include "setjmp.h" +#define LD_NAME L"gzip_ia64" + #define memzero(s, n) Memset((VOID *)(s), 0, (n)) #define memcpy(a,b,n) Memcpy((VOID *)(a),(b),(n)) @@ -68,6 +70,7 @@ typedef struct segment { #define CHUNK_FL_VALID 0x1 #define CHUNK_FL_LOAD 0x2 +#define CHUNK_FL_X 0x4 #define CHUNK_CAN_LOAD(n) chunks[(n)].flags |= CHUNK_FL_LOAD #define CHUNK_NO_LOAD(n) chunks[(n)].flags &= ~CHUNK_FL_LOAD @@ -391,6 +394,9 @@ first_block (const char *buf, long blocksize) continue; } + if (bswap32(phdrs[i].p_flags) & PF_X) + chunks[i].flags |= CHUNK_FL_X; + CHUNK_CAN_LOAD(i); /* mark no load chunk */ VERB_PRT(3, @@ -433,7 +439,7 @@ first_block (const char *buf, long blocksize) if (alloc_kmem((void *)low_addr, pages) == -1) { VOID *new_addr; - ERR_PRT((L"%s : AllocatePages(%d, 0x%lx) for kernel failed\n", LD_NAME, pages, low_addr)); + VERB_PRT(1, (L"%s : AllocatePages(%d, 0x%lx) for kernel failed\n", LD_NAME, pages, low_addr)); if (ia64_can_relocate() == 0) { ERR_PRT((L"relocation is disabled, cannot load kernel")); @@ -458,7 +464,7 @@ first_block (const char *buf, long blocksize) /* unsigned arithmetic */ load_offset = (UINTN) (new_addr - ROUNDDOWN((UINTN) low_addr,256*MB)); - ERR_PRT((L"low_addr=0x%lx new_addr=0x%lx offset=0x%lx", low_addr, new_addr, load_offset)); + VERB_PRT(1, (L"low_addr=0x%lx new_addr=0x%lx offset=0x%lx", low_addr, new_addr, load_offset)); /* * correct various addresses for non-zero load_offset @@ -566,6 +572,8 @@ tail: if (cnt > outcnt) cnt = outcnt; Memcpy(dst, src, cnt); + if (cp->flags & CHUNK_FL_X) + flush_dcache (dst, cnt); file_offset += cnt; outcnt -= cnt; diff --git a/ia64/gzip_loader.c b/ia64/gzip_loader.c index 4e06db4..a84851f 100644 --- a/ia64/gzip_loader.c +++ b/ia64/gzip_loader.c @@ -30,6 +30,8 @@ #include "loader.h" #include "gzip.h" +#define LD_NAME L"gzip_ia64" + static INTN gzip_probe_format(CHAR16 *kname) { diff --git a/ia64/plain_loader.c b/ia64/plain_loader.c index 92d009e..150f7a0 100644 --- a/ia64/plain_loader.c +++ b/ia64/plain_loader.c @@ -288,7 +288,7 @@ load_elf(fops_fd_t fd, kdesc_t *kd) if (alloc_kmem(low_addr, pages) == -1) { VOID *new_addr; - ERR_PRT((L"%s : AllocatePages(%d, 0x%lx) for kernel failed\n", LD_NAME, pages, low_addr)); + VERB_PRT(1, (L"%s : AllocatePages(%d, 0x%lx) for kernel failed\n", LD_NAME, pages, low_addr)); if (ia64_can_relocate() == 0) { ERR_PRT((L"relocation is disabled, cannot load kernel")); @@ -387,6 +387,8 @@ load_elf(fops_fd_t fd, kdesc_t *kd) ret = read_file(fd, filesz, (CHAR8 *)phdrs[i].p_paddr); if (ret == ELILO_LOAD_ABORTED) goto load_abort; if (ret == ELILO_LOAD_ERROR) goto out; + if (bswap32(phdrs[i].p_flags) & PF_X) + flush_dcache ((CHAR8 *)phdrs[i].p_paddr, filesz); /* * update file position diff --git a/ia64/private.h b/ia64/private.h index bb09faf..c8f34c7 100644 --- a/ia64/private.h +++ b/ia64/private.h @@ -31,5 +31,7 @@ extern INTN query_fpswa(VOID **); extern INTN ia64_can_relocate(); +extern void flush_dcache (CHAR8 *addr, UINT64 len); + #endif /* __ELILO_PRIVATE_IA64_H__ */ diff --git a/ia64/setjmp.S b/ia64/setjmp.S index ce7e67c..4bc2103 100644 --- a/ia64/setjmp.S +++ b/ia64/setjmp.S @@ -78,6 +78,7 @@ setjmp: /* __sigsetjmp(__jmp_buf buf, int savemask) */ + .proc __sigsetjmp __sigsetjmp: //.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(2) alloc loc1=ar.pfs,2,2,2,0 diff --git a/ia64/sysdeps.h b/ia64/sysdeps.h index ab447fb..e11e6b7 100644 --- a/ia64/sysdeps.h +++ b/ia64/sysdeps.h @@ -65,8 +65,11 @@ typedef struct ia64_boot_params { UINTN initrd_start; /* virtual address where the initial ramdisk begins */ UINTN initrd_size; /* how big is the initial ramdisk */ + UINTN vmcode_start; /* virtual address where the boot time vmcode begins */ + UINTN vmcode_size; /* how big is the boot module */ UINTN loader_addr; /* start address of boot loader */ UINTN loader_size; /* size of loader code & data */ + } boot_params_t; typedef struct sys_img_options { diff --git a/ia64/system.c b/ia64/system.c index 388d435..bb826ef 100644 --- a/ia64/system.c +++ b/ia64/system.c @@ -39,7 +39,7 @@ extern loader_ops_t plain_loader, gzip_loader; * IA-64 specific boot paramters initialization routine */ INTN -sysdeps_create_boot_params(boot_params_t *bp, CHAR8 *cmdline, memdesc_t *initrd, UINTN *cookie) +sysdeps_create_boot_params(boot_params_t *bp, CHAR8 *cmdline, memdesc_t *initrd, memdesc_t *vmcode, UINTN *cookie) { UINTN cols, rows; SIMPLE_TEXT_OUTPUT_INTERFACE *conout; @@ -64,7 +64,12 @@ sysdeps_create_boot_params(boot_params_t *bp, CHAR8 *cmdline, memdesc_t *initrd, bp->efi_memdesc_version = mdesc.desc_version; bp->command_line = (UINTN)cmdline; bp->initrd_start = (UINTN) initrd->start_addr; - bp->initrd_size = initrd->pgcnt << EFI_PAGE_SHIFT; + bp->initrd_size = initrd->size; + DBG_PRT((L"Got initrd @ 0x%lx (%d bytes)", initrd->start_addr, initrd->size)); + + bp->vmcode_start = (UINTN) vmcode->start_addr; + bp->vmcode_size = vmcode->size; + DBG_PRT((L"Got vmcode @ 0x%lx (%d bytes)", vmcode->start_addr, vmcode->size)); /* fetch console parameters: */ conout = systab->ConOut; @@ -135,3 +140,20 @@ sysdeps_initrd_get_addr(kdesc_t *kd, memdesc_t *imem) return 0; } +/* Flush data cache [addr; addr + len], and sync with icache. */ +void +flush_dcache (CHAR8 *addr, UINT64 len) +{ + /* Cache line length is at least 32. */ + UINT64 a = (UINT64)addr & ~0x1f; + + VERB_PRT(3, Print(L"Flush 0x%lx-", a)); + + /* Flush data. */ + for (len = (len + 31) & ~0x1f; len > 0; len -= 0x20, a += 0x20) + asm volatile ("fc %0" : : "r" (a)); + /* Sync and serialize. Maybe extra. */ + asm volatile (";; sync.i;; srlz.i;;"); + + VERB_PRT(3, Print(L"0x%lx\n", a)); +} diff --git a/ia64/inflate.c b/inflate.c similarity index 97% rename from ia64/inflate.c rename to inflate.c index 8273c98..843c93b 100644 --- a/ia64/inflate.c +++ b/inflate.c @@ -1053,42 +1053,6 @@ makecrc(void) 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! */ diff --git a/initrd.c b/initrd.c index 92b6f44..09ed0f0 100644 --- a/initrd.c +++ b/initrd.c @@ -29,7 +29,7 @@ #include "elilo.h" /* - * This function allocates memory for the initial ramdisk (initrd) and loads it to memory + * This function allocates memory for file image and loads it to memory * OUTPUTS: * - ELILO_LOAD_SUCCESS: if everything works * - ELILO_LOAD_ABORTED: in case the user decided to abort loading @@ -38,12 +38,12 @@ * Adapted from Bill Nottingham patch for ELI. */ INTN -load_initrd(CHAR16 *filename, memdesc_t *initrd) +load_file(CHAR16 *filename, memdesc_t *image) { EFI_STATUS status; - VOID *start_addr = initrd->start_addr; - UINT64 size = 0; + VOID *start_addr = image->start_addr; UINTN pgcnt; + UINT64 size = 0; fops_fd_t fd; INTN ret = ELILO_LOAD_ERROR; @@ -53,46 +53,48 @@ load_initrd(CHAR16 *filename, memdesc_t *initrd) /* Open the file */ status = fops_open(filename, &fd); if (EFI_ERROR(status)) { - ERR_PRT((L"Open initrd file %s failed: %r", filename, status)); + ERR_PRT((L"Open file %s failed: %r", filename, status)); return -1; } - DBG_PRT((L"initrd_open %s worked", filename)); + DBG_PRT((L"open %s worked", filename)); /* warning: this function allocates memory */ status = fops_infosize(fd, &size); if (EFI_ERROR(status)) { - ERR_PRT((L"Couldn't read initrd file %s info %r",filename, status)); + ERR_PRT((L"Couldn't read file %s info %r", filename, status)); goto error; } + image->size = size; + /* round up to get required number of pages (4KB) */ - initrd->pgcnt = pgcnt = EFI_SIZE_TO_PAGES(size); - - + image->pgcnt = pgcnt = EFI_SIZE_TO_PAGES(image->size); start_addr = alloc_pages(pgcnt, EfiLoaderData, start_addr ? AllocateAddress : AllocateAnyPages, start_addr); if (start_addr == NULL) { - ERR_PRT((L"Failed to allocate %d pages for initrd", pgcnt)); + ERR_PRT((L"Failed to allocate %d pages for %s image", pgcnt, + filename)); goto error; } - VERB_PRT(2, Print(L"initrd: total_size: %ld bytes base: 0x%lx pages %d\n", - size, (UINT64)start_addr, pgcnt)); + VERB_PRT(2, Print(L"%s image: total_size: %ld bytes base: 0x%lx " + "pages %d\n", filename, image->size, + (UINTN)start_addr, pgcnt)); - Print(L"Loading initrd %s...", filename); + Print(L"Loading file %s...", filename); - ret = read_file(fd, size, start_addr); + ret = read_file(fd, image->size, start_addr); fops_close(fd); if (ret != ELILO_LOAD_SUCCESS) { - ERR_PRT((L"read initrd(%s) failed: %d", filename, ret)); + ERR_PRT((L"read image(%s) failed: %d", filename, ret)); goto error; } Print(L"done\n"); - initrd->start_addr = start_addr; + image->start_addr = start_addr; return ELILO_LOAD_SUCCESS; @@ -103,8 +105,9 @@ error: * make sure nothing is passed to kernel * in case of error. */ - initrd->start_addr = 0; - initrd->pgcnt = 0; + image->start_addr = 0; + image->pgcnt = 0; + image->size = 0; return ret; }