diff --git a/ChangeLog b/ChangeLog index 12d2ddf..2ad51fe 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,36 @@ -2009-10-22 signed off by Jason Fleischli +2013-03-27 signed off by Jason Fleischli + * ADD CROSSBUILD + * intake edited version of Debian x86x crossbuild patches. + * Fixed Makefile clean to include crossbuild envs. + * Fixed ia32 system.c compile warning + * Simplified efi no GOP warning so it doesnt look like an error. + * MAJOR: Fixed Fault crash when EFI memory map changes from under elilo. + (from an outside interrupt in this case). When the EFI Memory map + changes after elilo has already built boot params to pass to the + kernel the EFI call to ExitBootSvcs just prior to boot will fail + because elilo has the old map key. This is valid EFI behavior, elilo + retries to pick up the new memory map and valid key but had already + freed the start params portion of boot params resulting in a NULL + DEREF crash reset. + * Add console reset call during initialization. thanks A. Steinmetz + * minor bugfix, fixed -m option broken. thanks Allan-lsk. + * tag 3_16 for release + +2011-1-10 signed off by Jason Fleischli + * Uptake of SUSE patches + - add sysfs support for efi vars (formerly /proc/efi/vars) + - fix strncpy overflow + - fix bzimage alloc + - cleanups + - support longer command line + - yet some more mac fixes + - align elilo with latest kernel boot protocol format. + - new memory management strategy for initrd and kernel image loading. + * add force text mode command line option. + * replace error output on GOP handle failed, downgraded to normal + print status with more informative output. + +2009-10-22 signed off by Jason Fleischli * elilo 3.12 release commit * Added additional #defines for debug levels to reduce the output * Added Mac console patch rework from Julien Blache @ debian @@ -20,7 +52,8 @@ x86_64... this is a legacy design hold over from original design and needs to be re-written to do dynamic size memory management based on the size of the actual vmlinuz image, as ia64/gzip does. -2008-04-02 signed off by Jason Fleischli + +2008-04-02 signed off by Jason Fleischli * elilo 3.10 release commit * Bumped version string to 3.10 * added PTR_FMT 32bit & 64bit pointer translation for correct output @@ -39,9 +72,11 @@ subtree * bugfix loader_probe now correctly errors out if no loaders registered. -2008-01-11 signed off by Jason Fleischli + +2008-01-11 signed off by Jason Fleischli * Various compile warning cleanups. -2008-01-03 signed off by Jason Fleischli + +2008-01-03 signed off by Jason Fleischli * Patch contribution from Scott Davilla when x is zero for the first call to add_memory_region, e820_map[-1] will access memory outside the bounds of e820_map. While this does @@ -49,7 +84,8 @@ above the e820_map[0] location that should have been zeroed by the bootloader, the code should not access outside the bounds of structures. -2008-01-03 Jason Fleischli + +2008-01-03 Jason Fleischli * initrd.c -- Let the allocator decide where to grab the memory from the efi memory map. Current start_addr=image->start_addr forces the same efi region everytime, and has a 7mb limit. ramdisk (initrd.img) @@ -57,9 +93,11 @@ the image->start_addr resulting in an elilo hang. Leaving start_addr NULL at initialization forces alloc_pages to get a memory region sufficient for the size of the initrd image. -2007-12-19 Jason Fleischli + +2007-12-19 Jason Fleischli * bumping version string to 3.8 -2007-12-19 Jason Fleischli + +2007-12-19 Jason Fleischli * MORE PATCHES FROM INTEL FOR IA32 X86_64. * Fix compile warning for cmdline_addr assignment. * Fix an issue caused by uninitialized e820_nr_map in fill_e820map. @@ -83,12 +121,14 @@ EFI framebuffer type ID setting code in ELILO is changed accordingly. * E820 memory map is added to IA32 to make it possible for Linux kernel not to depend on EFI memory map on EFI 32. -2007-09-27 Jason Fleischli + +2007-09-27 Jason Fleischli * updating changelog for last commit that was omitted * incorporating AGriffis patches to enhance parsing passes root= option to kernel options and accounts for -- option designation. -2007-07-19 Jason Fleischli + +2007-07-19 Jason Fleischli * Integrated x86_64 support patches from Chandramouli Narayanan changes summarized in following bullets. * alloc.c -- adds patch contributors credit to copyright @@ -159,13 +199,17 @@ * x86_64/sysdeps.c -- new file, system stuff for x86_64 * elilo.txt -- documentation update, add Intel to copyright * README.gnu-efi -- documentation update for x86_64 + 2006-01-27 Alex Williamson * Found a couple more places where vmcode isn't zeroed, causing the option to get carried over to labels it shouldn't. + 2006-01-09 Brett Johnson * Released 3.6 + 2005-12-22 Alex Williamson * Fixed vmcode_name initialization in textmenu chooser + 2005-12-01 Alex Williamson * Applied patch from Fred Yang to support the vmm= boot option. This option specifies the kernel image for a @@ -179,29 +223,37 @@ 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. + 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 * integrated ia32 updates from Matt Tolentino + 2003-08-13 Stephane Eranian * updated elilo.txt and netbooting.txt * fix a bug in choosers/simple.c:print_infos(). @@ -214,37 +266,47 @@ * updated simple chooser set of builtin command keys * command keys are only valid if first on the line * increase default buffer size and increment when netbooting + 2003-06-04 Stephane Eranian * fix fs/netfs.c to work with recent version of EFI (14.61 or higher) which do not have the TFTP problem anymore. fix submitted by Guy Laborde + 2003-04-21 Stephane Eranian * ext2fs support is turned off by default to avoid problems with ext3-formatted partitions. * added gcc version check. MUST use 3.0 or higher + 2003-03-03 Stephane Eranian * added check on dev_tab in fs/*fs.c:*_uninstall() + 2003-02-07 Stephane Eranian * clean up in glue_localfs.c w.r.t. CHAR16 in set_default_path() * added support for extracting basename of bootloader path when using BOOTP (DHCP) only. The prefix is then used for all files open via netfs. Suggestion and initial patch by Guy Laborde from HP. + 2003-01-28 Stephane Eranian * fix the set_default_path() routine in glue_localfs.c. It would not correctly get the basename of the devpath. This caused the elilo.conf not to be found sometimes. + 2003-01-21 Stephane Eranian * fix bug in glue_netfs.c convert_ip2decstr() which caused some IP addresses to be incorrectly converted to strings. + 2002-11-01 Stephane Eranian * fix bug in -r option for IA64. There is no argument to this option. + 2002-10-15 Stephane Eranian * fixed a double free bug for the kernel memory in case of abort. (bug spotted by Levent Akyl from Intel) * released 3.3a + 2002-09-14 Stephane Eranian * applied patch from Andreas Schwab to eliloalt.c. eliloalt dynamically selects a variable in /proc/efi/vars. + 2002-09-12 Stephane Eranian * removed extra free() from fs/ext2fs.c:ext2fs_init_state(). Bug report and fix by NOMURA Jun'ichi @@ -252,25 +314,31 @@ was bigger than the 128KB limit of EFI causing some weird fimrware errors. bug reported by OMURA Jun'ichi * on IA-64 forbid the use of f32-f127 by the compiler (EFI spec) + 2002-09-10 Stephane Eranian * fix a bug in argify() that was causing an EFI assertion when aborting at the elilo prompt when netbooted. + 2002-08-26 Stephane Eranian * fixed devschemes/simple.c to use SPrint() instead of its own buggy conversion code (spotted by Richard Hirst). * fix bug in argify() when there was no NULL character in the string. * released 3.3 + 2002-08-19 Stephane Eranian * added fpswa.txt in the docs directory * updated elilo.txt + 2002-08-15 Stephane Eranian * added -F file option for IA-64 to allow a specific fpswa driver to be loaded * fixed fpswa.c to try and load the driver from all accessible partitions * added support to load (plain or gzipped) big-endian ELF/ia64 binaries using p_paddr. * fixed problem in fs/netfs.c causing large (>4MB) binaries to fail the Mftp() call + 2002-06-13 Stephane Eranian * Changed the despecialization character for the variables from \\ to & to avoid conflicts with \\ as a path separator + 2002-06-11 Stephane Eranian * fixed the return value in efi_main(). elilo was always returning success even in case of failure. Bug reported by Egan Ford @@ -280,11 +348,13 @@ compliant with EFI spec with regards to where it looks for files. With this patch, elilo will look in the directory it was loaded from, not on the root of the partition anymore. + 2002-03-04 Stephane Eranian * 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 + 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. @@ -292,19 +362,24 @@ * added support for hostname,domain name extraction in fs/netfs.c * fixed all known bugs in alternate.c * integrated patch from SGI to fix load offset for relocatable kernels (Jack Steiner, Brent Casavant) + 2002-02-21 Michael Johnston and Chris Ahna * major update to ia32 support: can now boot 2.4.x, and 2.2.x kernels + 2002-02-20 Stephane Eranian * fixed missing netfs_fd_free() in case of file not found in netfs.c + 2002-02-19 Stephane Eranian * added support for substitution variables (vars.c) * changed the bootparam structure size back to 4kB * added support to simple to print final command line option with tab key * got rid of all the \r characters in strings use only \n (adjust emulator) * added EFICRT0 variable in Makefile to indicate location of loader script+crt0 + 2002-02-14 Stephane Eranian * added support for message= option to simple chooser * added support for description= option to simple chooser + 2002-02-13 Stephane Eranian * choosers/textmenu.c: new textmenu chooser (by rhirst@linuxcare.com) used by Debian * config.c: added support for dynamic global/per-image option management @@ -333,6 +408,7 @@ mode was specified in config file. In this case, we now autoboot and ignore the prompt directive. * updated elilo.txt + 2001-08-15 Brent Casavant * fix a bug in config.c:find_option() where it would do a strXcmp() on a NULL string. diff --git a/Make.defaults b/Make.defaults index f5dca13..f372a1b 100644 --- a/Make.defaults +++ b/Make.defaults @@ -61,14 +61,17 @@ EFICRT0 = /usr/lib CDIR := $(shell if [ "$$PWD" != "" ]; then echo $$PWD; else pwd; fi) TOPDIR = +ALLSUBDIRS = ia32 ia64 x86_64 fs choosers devschemes tools -ARCH = $(shell uname -m | sed s,i[3456789]86,ia32,) +HOSTARCH = $(shell dpkg-architecture -qDEB_BUILD_ARCH | sed s,i[3456789]86,ia32, | sed s,amd64,x86_64, ) +ARCH := $(shell dpkg-architecture -qDEB_BUILD_ARCH | sed s,i[3456789]86,ia32, | sed s,amd64,x86_64, ) INCDIR = -I. -I$(TOPDIR) -I$(EFIINC) -I$(EFIINC)/$(ARCH) -I$(EFIINC)/protocol -I$(TOPDIR)/efi110 CPPFLAGS = -DCONFIG_$(ARCH) OPTIMFLAGS = -O2 DEBUGFLAGS = -Wall -CFLAGS = $(OPTIMFLAGS) -fno-strict-aliasing -fpic -fshort-wchar $(DEBUGFLAGS) +CFLAGS = $(ARCH3264) $(OPTIMFLAGS) -fno-stack-protector -fno-strict-aliasing -fpic -fshort-wchar $(DEBUGFLAGS) +ASFLAGS = $(ARCH3264) LDFLAGS = -nostdlib -znocombreloc INSTALL = install @@ -108,10 +111,30 @@ OBJCOPY = $(prefix)objcopy # Use Modified binutils that supports x86_64 using UEFI ABI ifeq ($(ARCH), x86_64) + ifeq ($(HOSTARCH), ia32) + ARCH3264 = -m64 + LD3264 = -melf_x86_64 + + GNUEFILIB := $(GNUEFILIB)64 + EFILIB := $(EFILIB)64 + EFICRT0 := $(EFICRT0)64 + endif + CFLAGS += -DEFI_FUNCTION_WRAPPER OBJCOPY = /usr/bin/objcopy endif +ifeq ($(ARCH), ia32) + ifeq ($(HOSTARCH), x86_64) + ARCH3264 = -m32 + LD3264 = -melf_i386 + + GNUEFILIB := /usr/lib32 + EFILIB := /usr/lib32 + EFICRT0 := /usr/lib32 + endif +endif + ifeq ($(ARCH),ia64) GCC_VERSION=$(shell $(CROSS_COMPILE)$(CC) -v 2>&1 | fgrep 'gcc version' | cut -f3 -d' ' | cut -f1 -d'.') diff --git a/Makefile b/Makefile index 613b597..6315960 100644 --- a/Makefile +++ b/Makefile @@ -25,15 +25,19 @@ # to use this program. # -include Make.defaults -TOPDIR=. +SRCDIR = . + +VPATH = $(SRCDIR) + +include $(SRCDIR)/Make.defaults +TOPDIR = $(SRCDIR) CRTOBJS = $(EFICRT0)/crt0-efi-$(ARCH).o LDSCRIPT = $(EFICRT0)/elf_$(ARCH)_efi.lds LDFLAGS += -T $(LDSCRIPT) -shared -Bsymbolic -L$(EFILIB) -L$(GNUEFILIB) $(CRTOBJS) -LOADLIBES = -lefi -lgnuefi $(shell $(CC) -print-libgcc-file-name) +LOADLIBES = -lefi -lgnuefi $(shell $(CC) $(ARCH3264) -print-libgcc-file-name) FORMAT = efi-app-$(ARCH) FILESYSTEM = @@ -81,18 +85,19 @@ elilo.efi: elilo.so elilo.so: $(FILES) -elilo.o : elilo.c +elilo.o : elilo.c $(ARCH)/sysdeps.h fileops.o : Make.defaults chooser.o : Make.defaults $(SUBDIRS): dummy - $(MAKE) -C $@ + mkdir -p $@ + $(MAKE) -C $@ -f $(SRCDIR)/../$@/Makefile SRCDIR=$(SRCDIR)/../$@ ARCH=$(ARCH) dummy: clean: - @set -e ; for d in $(SUBDIRS) ; do $(MAKE) -C $$d $@ ; done + @set -e ; for d in $(ALLSUBDIRS) ; do $(MAKE) -C $$d $@ ; done rm -f $(TARGETS) *~ *.so $(FILES) .PRECIOUS: elilo.so @@ -106,4 +111,4 @@ ifeq ($(GCC_VERSION),2) @exit 1 endif -include Make.rules +include $(SRCDIR)/Make.rules diff --git a/alloc.c b/alloc.c index 6f463e4..cd67c38 100644 --- a/alloc.c +++ b/alloc.c @@ -110,7 +110,7 @@ alloc(UINTN size, EFI_MEMORY_TYPE type) } alloc_add(tmp, size, ALLOC_POOL); #ifdef DEBUG_MEM - DBG_PRT((L"alloc: allocated %d bytes @[" PTR_FMT "-" PTR_FMT "]\n", size, tmp, tmp+size)); + DBG_PRT((L"alloc: allocated %d bytes @[" PTR_FMT "-" PTR_FMT "]", size, tmp, tmp+size)); #endif return tmp; } @@ -140,7 +140,7 @@ alloc_pages(UINTN pgcnt, EFI_MEMORY_TYPE type, EFI_ALLOCATE_TYPE where, VOID *ad alloc_add(addr, pgcnt, ALLOC_PAGES); - DBG_PRT((L"allocator: allocated %d pages @0x%lx\n", pgcnt, tmp)); + DBG_PRT((L"allocator: allocated %d pages @" PTR_FMT, pgcnt, tmp)); return addr; } @@ -162,7 +162,7 @@ free(VOID *addr) return; found: #ifdef DEBUG_MEM - DBG_PRT((L"free: %s @" PTR_FMT " size=%d\n", + DBG_PRT((L"free: %s @" PTR_FMT " size=%d", p->type == ALLOC_POOL ? L"Pool": L"Page", addr, p->size)); #endif @@ -196,7 +196,7 @@ free_all(VOID) while(used_allocs) { #ifdef DEBUG_MEM - DBG_PRT((L"free_all %a @ " PTR_FMT "\n", used_allocs->type == ALLOC_POOL ? "pool" : "pages", used_allocs->addr)); + DBG_PRT((L"free_all %a @ " PTR_FMT, used_allocs->type == ALLOC_POOL ? "pool" : "pages", used_allocs->addr)); #endif if (used_allocs->type == ALLOC_POOL) uefi_call_wrapper(BS->FreePool, 1, used_allocs->addr); @@ -217,7 +217,15 @@ INTN alloc_kmem_anywhere(VOID **start_addr, UINTN pgcnt) { void * tmp; - if ((tmp = alloc_pages(pgcnt, EfiLoaderData, AllocateAnyPages, *start_addr)) == 0) return -1; + /* + * During "AllocateAnyPages" *start_addr will be ignored. + * Therefore we can safely subvert it to reuse this function with + * an alloc_kmem_anyhwere_below() semantic... + */ + tmp = alloc_pages(pgcnt, EfiLoaderData, + (*start_addr) ? AllocateMaxAddress : AllocateAnyPages, + *start_addr); + if (tmp == NULL) return -1; kmem_addr = tmp; kmem_pgcnt = pgcnt; @@ -241,7 +249,7 @@ VOID free_kmem(VOID) { #ifdef DEBUG_MEM - DBG_PRT((L"free_kmem before (" PTR_FMT ", %d)\n", kmem_addr, kmem_pgcnt)); + DBG_PRT((L"free_kmem before (" PTR_FMT ", %d)", kmem_addr, kmem_pgcnt)); #endif if (kmem_addr && kmem_pgcnt != 0) { free(kmem_addr); @@ -249,7 +257,7 @@ free_kmem(VOID) kmem_pgcnt = 0; } #ifdef DEBUG_MEM - DBG_PRT((L"free_kmem after (" PTR_FMT ", %d)\n", kmem_addr, kmem_pgcnt)); + DBG_PRT((L"free_kmem after (" PTR_FMT ", %d)", kmem_addr, kmem_pgcnt)); #endif } diff --git a/bootparams.c b/bootparams.c index da3d664..12d11ce 100644 --- a/bootparams.c +++ b/bootparams.c @@ -67,9 +67,6 @@ create_boot_params(CHAR16 *args, memdesc_t *initrd, memdesc_t *vmcode, UINTN *co /* * 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); @@ -96,6 +93,8 @@ create_boot_params(CHAR16 *args, memdesc_t *initrd, memdesc_t *vmcode, UINTN *co */ Memset(bp, 0, BOOT_PARAM_MEMSIZE); + U2ascii(args, cp, cmdline_size); + if (sysdeps_create_boot_params(bp, cp, initrd, vmcode, cookie) == -1) return 0; /* diff --git a/choosers/Makefile b/choosers/Makefile index 31b10d0..85d31c7 100644 --- a/choosers/Makefile +++ b/choosers/Makefile @@ -23,10 +23,15 @@ # to use this program. # -include ../Make.defaults -include ../Make.rules +SRCDIR = . + +VPATH = $(SRCDIR) + +include $(SRCDIR)/../Make.defaults +include $(SRCDIR)/../Make.rules + +TOPDIR=$(SRCDIR)/.. -TOPDIR=$(CDIR)/.. FILES= @@ -42,17 +47,14 @@ TARGET=choosers.o all: $(TARGET) -$(TARGET): check-choosers $(TOPDIR)/Make.defaults $(FILES) - $(LD) -o $@ -r $(FILES) - -clean: - $(RM) -f $(TARGET) $(FILES) - -check-choosers: - @if [ -n "$(FILES)" ]; then \ - exit 0; \ - else \ +$(TARGET): $(TOPDIR)/Make.defaults $(FILES) + @if [ -z "$(FILES)" ]; then \ echo "You need to define at least one chooser in Make.defaults"; \ exit 1; \ fi + $(LD) $(LD3264) -o $@ -r $(FILES) + + +clean: + $(RM) -f $(TARGET) $(FILES) diff --git a/choosers/simple.c b/choosers/simple.c index f064e12..d0c38f7 100644 --- a/choosers/simple.c +++ b/choosers/simple.c @@ -41,8 +41,8 @@ static VOID display_label_info(CHAR16 *name) { CHAR16 *desc; - CHAR16 initrd_name[CMDLINE_MAXLEN]; - CHAR16 vmcode_name[CMDLINE_MAXLEN]; + CHAR16 initrd_name[PATHNAME_MAXLEN]; + CHAR16 vmcode_name[PATHNAME_MAXLEN]; CHAR16 options_tmp[CMDLINE_MAXLEN]; CHAR16 options[CMDLINE_MAXLEN]; CHAR16 kname[FILENAME_MAXLEN]; @@ -254,10 +254,10 @@ simple_choose(CHAR16 **argv, INTN argc, INTN index, CHAR16 *kname, CHAR16 *cmdli # define BOOT_IMG_STR L"BOOT_IMAGE=" CHAR16 buffer[CMDLINE_MAXLEN]; CHAR16 alt_buffer[CMDLINE_MAXLEN]; - CHAR16 initrd_name[CMDLINE_MAXLEN]; - CHAR16 vmcode_name[CMDLINE_MAXLEN]; + CHAR16 initrd_name[PATHNAME_MAXLEN]; + CHAR16 vmcode_name[PATHNAME_MAXLEN]; CHAR16 args[CMDLINE_MAXLEN]; - CHAR16 devname[CMDLINE_MAXLEN]; + CHAR16 devname[PATHNAME_MAXLEN]; CHAR16 dpath[FILENAME_MAXLEN]; CHAR16 *slash_pos, *colon_pos, *backslash_pos; UINTN len; @@ -290,8 +290,9 @@ restart: if (elilo_opt.prompt) { console_textmode(); - ret = select_kernel(buffer, sizeof(buffer)); + ret = select_kernel(buffer, CMDLINE_MAXLEN); if (ret == -1) return -1; + /* this function takes really the number of bytes ... */ argc = argify(buffer,sizeof(buffer), argv); index = 0; } diff --git a/choosers/textmenu.c b/choosers/textmenu.c index ac282c0..52021a9 100644 --- a/choosers/textmenu.c +++ b/choosers/textmenu.c @@ -363,10 +363,10 @@ 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 initrd_name[PATHNAME_MAXLEN]; + CHAR16 vmcode_name[PATHNAME_MAXLEN]; CHAR16 args[CMDLINE_MAXLEN]; - CHAR16 devname[CMDLINE_MAXLEN]; + CHAR16 devname[PATHNAME_MAXLEN]; CHAR16 dpath[FILENAME_MAXLEN]; CHAR16 *slash_pos, *colon_pos, *backslash_pos; UINTN len; diff --git a/config.c b/config.c index 5ad8de6..d144c9f 100644 --- a/config.c +++ b/config.c @@ -56,7 +56,7 @@ */ #define ELILO_DEFAULT_CONFIG L"elilo.conf" -#define MAX_STRING CMDLINE_MAXLEN +#define MAX_STRING 512 #define CONFIG_BUFSIZE 512 /* input buffer size */ /* @@ -71,7 +71,7 @@ typedef struct boot_image { struct boot_image *next; CHAR16 label[MAX_STRING]; CHAR16 kname[FILENAME_MAXLEN]; - CHAR16 options[MAX_STRING]; + CHAR16 options[CMDLINE_MAXLEN]; CHAR16 initrd[FILENAME_MAXLEN]; CHAR16 vmcode[FILENAME_MAXLEN]; CHAR16 root[FILENAME_MAXLEN]; @@ -100,7 +100,7 @@ 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 options[CMDLINE_MAXLEN]; CHAR16 default_image_name[MAX_STRING]; CHAR16 message_file[MAX_MESSAGES][FILENAME_MAXLEN]; CHAR16 chooser[FILENAME_MAXLEN];/* which image chooser to use */ @@ -909,10 +909,10 @@ print_label_list(VOID) { boot_image_t *img, *dfl = global_config.default_image; - if (dfl) Print(L"\t%s\n", dfl->label); + if (dfl) Print(L" %s\n", dfl->label); for (img = image_list; img; img = img->next) { - if (img != dfl) Print(L"\t%s\n", img->label); + if (img != dfl) Print(L" %s\n", img->label); } } diff --git a/devschemes/Makefile b/devschemes/Makefile index 6ac05af..5328cb1 100644 --- a/devschemes/Makefile +++ b/devschemes/Makefile @@ -23,10 +23,15 @@ # to use this program. # -include ../Make.defaults -include ../Make.rules +SRCDIR = . + +VPATH = $(SRCDIR) + +include $(SRCDIR)/../Make.defaults +include $(SRCDIR)/../Make.rules + +TOPDIR=$(SRCDIR)/.. -TOPDIR=$(CDIR)/.. FILES=simple.o @@ -40,7 +45,7 @@ all: $(TARGET) # without doing make clean. # $(TARGET): $(FILES) - $(LD) -r -o $@ $(FILES) + $(LD) $(LD3264) -r -o $@ $(FILES) clean: $(RM) -f $(TARGET) $(FILES) diff --git a/docs/README.txt b/docs/README.txt new file mode 100644 index 0000000..a3fcc69 --- /dev/null +++ b/docs/README.txt @@ -0,0 +1,522 @@ + -------------------------------------------------------------------- + ELILO.EFI: Linux boot loader for + EFI/IA-64,EFI/IA-32 and EFI/x86_64 based systems + -------------------------------------------------------------------- + Stephane Eranian + + August 2003 + + Copyright (C) 2000-2012 Hewlett-Packard Co. + Copyright (C) 2006-2010 Intel Co. + + +I/ Introduction + ------------ + +This document describes how to use ELILO on for IA-64, IA-32 and x86_64 EFI-based platforms. +This document describes ELILO version 3.7 - 3.14. + +II/ Command line options + -------------------- + + elilo [-hDpPVvaE] [-d nsec] [-C config] [-i initrd] [-c chooser] [kernel [kernel options...]] + + -h Display a list of all possible command line options. + + -V Print the version number and exit. + + -d nsec Specify the number of 10th of seconds before loading the + kernel. + + -C file Specify the config file to use. The default is elilo.conf in the directory + that elilo.efi was loaded from. + + -P Verify config file syntax only. this option causes ELILO to + parse the config file and generate a report on the console. + No kernel is loaded. + + -v Turn on verbose mode. ELILO prints more message about what it + is doing. For each occurrence of this option the verbosity level + is increased by one. The maximum level is 5. + + -a Always check for alternate kernel image. The default behavior + of ELILO is to NOT look for an alternate image. This + option overrides this behavior and ELILO is checking for + alternate images no matter what. Alternate images are + specified using the EliloAlt EFI variable. + + -p force interactive prompt mode. Valid when no kernel image is + specified on the command line. + + -D print debug output. + + -E don't force EDD30 variable to TRUE when FALSE. + + -i file Use file as the initial ramdisk (initrd). + + -c name Specify which kernel chooser to use. Default is 'simple', and + the only other choice at present is 'textmenu'. + + In addition, elilo supports platform specific options: + + For IA-64: + ---------- + -r the kernel image can be relocated if initial load address is not + available. This options requires a special version of the kernel. + + -F file will try to load the FPSWA driver indicated by 'file'. Only this file + will be attempted. When no specific file is given, elilo will try + loading \efi\intel firmware\fpswa.efi from all accessible EFI system + partitions. + For IA-32: + ---------- + no option defined. + + All file names (including the kernel file) can include a device name using the + following syntax: + + dev_name:/path/to/my/kernel + + The 'dev_name' component depends on the naming scheme selected and the detected + devices for your system. Some choosers may print the information automatically + or on demand, see chooser specific documentation for more on this. See README.devschemes + for more information on device naming schemes. The slash character '/' can be used as + a directory separator on any file systems including the EFI file system (FAT32). + + For x86_64: + ---------- + none + +III/ Configuration File + ------------------ + + ELILO supports a config file with options similar to the LILO/x86 boot loader. + + Elilo will use the following sequence (shown in order) when looking for its config + file when none is specified on the command line: + + 1/ AABBCCDD.conf (netbooting with regular DHCP) + where AABBCCDD is the hexadecimal representation + of the IP address assigned during the DHCP phase. + + 2/ elilo-ia64.conf or elilo-ia32.conf or elilo-x86_64.conf + The choice depends on the client platform. This step allows + the same DHCP/PXE server to provide files for both types of clients. + + 3/ elilo.conf + + Unless explicitly specified on the command line, elilo looks for its config file + in the filesystem and directory it was loaded from. For instance, if elilo.efi + is invoked as: + + fs0:\> \efi\debian\elilo.efi + + Then elilo will look for its configuration file in fs0:\efi\debian and not + in the root directory of fs0:. The prefix fs0:\efi\debian will be used for + all other files that elilo needs to download when their paths are specified + as being relative. + + IMPORTANT: + This rule also applies when a specific config file is passed via the -C + option. For example: + + fs0:\> \efi\debian\elilo.efi -C elilo.conf + + This will look for elilo.conf in fs0:\efi\debian and not in fs0:\. + To get to the elilo.conf in fs0:\, you need to specify the absolute + path: + + fs0:\> \efi\debian\elilo.efi -C \elilo.conf + + + The configuration file is an ASCII file and not a UNICODE file. + + The config file contains additional options to change the behavior of the loader. + If the same option is specified in the config file AND on the command line, the + latter takes precedence. Not all options available in the config file have an + equivalent on command line. + + When elilo is invoked with the -h option, it prints the list of support command line + options but also the list of config file options. For each option it also prints + the type of data expected. + + The config file options are divided in 2 groups: + + + - image options which are specific to a particular kernel image. Each kernel image + must be identified with a logical name called a label. + + - global options which affect the behavior of ELILO and apply to all images. + + The ELILO config file follows the LILO/x86 syntax. First come the global + options, then the list of images and options for each of them, if + necessary. At least one image MUST be defined and it is possible to have + an empty list of global options. + + Options have types. Three types are defined: + - boolean: set or not set + - string : a string of characters which can be quoted if necessary + - number (in decimal) + - filename: a string interpreted as a file name + + + The config file supports the following options: + + Global Options: + --------------- + default=value Name the default image to boot. If not defined ELILO + will boot the first defined image. + + timeout=number The number of 10th of seconds to wait while in + interactive mode before auto booting default kernel. + Default is infinity. + + delay=number The number of 10th of seconds to wait before + auto booting when not in interactive mode. + Default is 0. + + prompt Force interactive mode + + verbose=number Set level of verbosity [0-5]. Default 0 (no verbose) + + root=filename Set global root filesystem for Linux/ia64 + + read-only Force root filesystem to be mounted read-only + + append=string Append a string of options to kernel command line + + initrd=filename Name of initrd file + + image=filename Define a new image + + chooser=name Specify kernel chooser to use: 'simple' or 'textmenu'. + + message=filename a message that is printed on the main screen if supported by + the chooser. + + fX=filename Some choosers may take advantage of this option to + display the content of a file when a certain function + key X is pressed. X can vary from 1-12 to cover + function keys F1 to F12. + + noedd30 do not force the EDD30 EFI variable to TRUE when FALSE. In other + words, don't force the EDD30 mode if not set. + + Image options: + -------------- + root=filename Set root filesystem for kernel + + read-only Force root filesystem to be mounted read-only + + append=string Append a string of options to kernel command line + + initrd=filename Name of initrd file + + label=string Logical name of image (used in interactive mode) + + description=string One line text description of the image. + + IA-64 specific options: + ----------------------- + + Global options: + --------------- + fpswa=file Specify the filename for a specific FPSWA to load. + If this option is used then no other file will be tried. + + relocatable In case of memory allocation error at initial load point of + kernel, allow attempt to relocate (assume kernels is relocatable) + + Image options: + -------------- + relocatable In case of memory allocation error at initial load point of + kernel, allow attempt to relocate (assume this kernel is relocatable) + + IA-32 specific options: + ----------------------- + legacy-free Indicate that the host machine does not have a legacy BIOS at all. + + + The user can specify a kernel and related kernel options using the image label. Alternatively, + the user can also specify a kernel file that is not specified in the config file. In any case, + some of the global options (such as append) are always concatenated to whatever the user type. + + x86_64 specific options: + ----------------------- + text-mode elilo>=3.14 boolean, image config option to force text console mode. + +IV/ Booting from the local system + ----------------------------- + + The elilo.efi binary must be in an EFI system partition (FAT32). The config + file, kernel image, and optional initrd ramdisk can be on the same partition + or even another EFI partition. In the following discussion we assume that all + files are on the same EFI partition which is recognized by the EFI shell (nshell) + as fs0. The kernel and initrd can be copied from the any linux filesystems to the + EFI partition using either the mtools (mcopy) or by mounting the EFI partition as + a vfat partition. However you do not really need this because most linux + distributions install both files in the EFI partition and mount this partition in /boot/efi. + + To boot a kernel, simply power cycle the machine. Once you get to the EFI + shell prompt, change to the filesystem that maps to the partition where elilo is. + + Shell> fs0: + fs0:\> + + You might need to make sure that the Shell Path is set such that it will load + ELILO from fs0:. You can verify this by typing: + fs0:\> set + path : fs0:\ + + At this point you can invoke ELILO: + + fs0:\> elilo + + If there is no config file, then it will: + - pick up the kernel image named vmlinux if it exists, otherwise it will abort. + - pass no argument to the kernel. + + You can specify the kernel image and its options on the command line. + For instance you can do: + + fs0:\> elilo vmlinux root=/dev/sda5 + + You can specify as many parameters as you want. The syntax follows the kernel + rule, i.e., list of value pairs (or even single values) separated by space. + A more complicated example would be: + + fs0:\> elilo -i initrd-2.4.9 vmlinuz-2.4.9 root=/dev/sda2 console=tty0 console="ttyS0,115200n8" + + In this example, notice the double quotes. They are required because the comma is a control + character for nshell. + + In the case a config file is found, then elilo will behave according to + the options in that file. However if elilo is invoked with command line options, they + will be combined or they will override (if conflicting) what is defined in the config file. + + As of version 3.3, elilo is fully compliant with the EFI specification (1.10) with regards + to where the bootloader (elilo.efi) must be located in the EFI system partition. In + section 11.2.1.3 of the EFI1.10 specification, it is said that in order to avoid conflicts + between various loaders for various OSes or distributions of the same OS, every vendor MUST + use a dedicated directory: \EFI\vendor\. The bootloader must be placed in this directory. + This has always been possible as this is a matter of creating the directory and copying + the elilo.efi file in it. However up until version 3.3, elilo would look for its config file + and kernel/initrd in the root (/) of the partition it was loaded from. As of version 3.3, + elilo will now ONLY look for its configuration file FROM THE DIRECTORY IT WAS LOADED FROM. + The same applies to the kernel and initrd files unless absolute paths are specified. Let us + look at a simple example: + + - suppose elilo.efi is in \EFI\DIST if fs0: (for the EFI Shell) + + - if you invoke elilo as follows: + + fs0:\> \efi\dist\elilo -v -p + default file path: \efi\dist\ + config file : \efi\dist\elilo.conf + ELILO boot: + + + Note that this is the same if you invoke elilo directly from \efi or \efi\dist. + + File references in the configuration file are treated as relative to the directory + elilo was loaded from except if they use an absolute path. + + As of version 3.4 a similar rule applies to the network boot sequence, see netbooting.txt + for details. + +V/ Interactive mode + ---------------- + + Elilo can be forced into interactive mode using the "prompt" option in the config + file or with the -p option. In this mode, the user can select a kernel to load. + + The interface depends on the chooser, it may be a simple command line prompt as provided + by the simple chooser or a more sophisticated screen with scroll menus as provided by + textmenu. Most choosers depends on the elilo config file to get the information they + display. The simple chooser can operated without the elilo config file. However it + is always better to have this file, to create handy logical names for each possible + boot choices. The logical names are specified with the "label" option in the config + file. They represent a specific kernel "image" and its specific options. + + In elilo, the user can select a particular kernel image using the corresponding label + name. A simple example is as follows: + + If we suppose that the following is defined in elilo.conf: + + image=vmlinuz-2.4.9 + label=linux-up + initrd=initrd-2.4.9 + root=/dev/sda2 + append="console=tty0 console=ttyS0,115200n8" + + then the user can specify linux-up at the prompt and elilo will load the + vmlinuz-2.4.9 kernel file and the initrd-2.4.9 ramdisk and will pass + + "root=/dev/sda2 console=tty0 console=ttyS0,115200n8" + + as command line arguments to the kernel. + + This behavior is identical to Lilo/x86. However, elilo further allows the user + to specify actual kernel files names as well, i.e., kernels that are not defined + in the configuration file. If we reuse the above example and the simple chooser, + the user can type: + + ELILO boot: vmlinux-2.4.18 root=/dev/sda2 + + and elilo will boot the vmlinuz-2.4.18 kernel if it exists. + +VI/ The alternate kernel image + -------------------------- + + Oftentimes when debugging kernels you want to reboot the machine once with + your test kernel and, if something goes wrong, you want to fall back to a more + stable kernel. In addition you want to be able to do this from a remote machine. + Many things can go wrong when doing kernel debugging. It could be that you don't + even reach user-mode. In this case however, you still want to fall back to + a stable kernel. The feature you'd like from a boot loader is 'boot once and + then fall back to safe kernel'. + + Elilo offers this feature and it's called 'alternate kernel image'. + You can configure elilo to load a kernel only once and then whatever + happens the next reboot falls back to a different kernel hopefully more stable. + + To do this, elilo relies on an EFI variable called 'EliloAlt' with a NULL GUID. + The content of this variable is a UNICODE string containing the kernel file name + and its command line options. + + When the -a option is specified on the command line or if the "checkalt" option + is present in the config file, elilo will check for the presence of this variable. + If found and the content is a valid UNICODE string, elilo will use it as the kernel + to boot. There is no verification made on the validity of the kernel name or options. + Then the variable is deleted. If the variable is rejected because it does not look + sane, it is also deleted. + + The variable can be set from a running Linux system using the /proc/efi/vars + interface. In the tools directory of this package, there is a Linux tool called + elilovar which can be used to create, modify, print, and delete the EliloAlt + variable. Refer to eliloalt.txt for more information on this tool. + +VII/ Auto booting the machine + ----------------------- + + Once you're satisfied with your machine setup, it is good to install an + auto boot procedure. You have two options to do this: + - from the EFI boot manager menu + - from the EFI shell + + The first option is preferred and is used by most Linux distributions. + Elilo can be invoked directly from the boot manager. You need to get into + the 'boot maintenance' menu and use load file a file. This can be tedious + so instead it is recommended that you use a Linux tool called efibootmgr + which is also shipped in most distributions. With this tool, you can + create your own boot option and change the boot order. + + + + The second approach use the EFI shell and a shell script with a special name: 'startup.nsh'. + + When the system boots, it looks for EFI partitions and if it finds + a 'startup.nsh' file in ANY of these it will jumpstart execution from it. + + So the typical way of auto booting your Linux/ia64 system is to simply create + such a file with the following content: + + # cat /boot/startup.nsh + elilo vmlinuz root=/dev/sda2 + + Of course, this can be simplified if there is a configuration file. + + +VII/ Netbooting + ---------- + + Please refer to netbooting.txt for a complete description of how to boot + from the network. + + +XII/ Booting on EFI/ia32 platforms + ----------------------------- + + Until PC comes with the EFI firmware built in, you need to boot from a + floppy that has the EFI firmware on it. Such floppy can be + constructed from the EFI sample implementation and toolkit that is + available from the Intel Developer Web site at: + + http://developer.intel.com/technology/efi/ + + To use elilo on IA-32, you can put it on a floppy and + on a FAT32 partition (msdos partition). You can also + netbooting if you network adapter has support for UNDI/PXE. + + Elilo/ia32 is capable of booting unmodified 2.2.x. and 2.4.x kernels + as they are shipped by distributors today (such as Redhat7.2). You don't need + to recompile the kernel with special options. Elilo ONLY takes compressed kernel + image which are typically obtained via a 'make bzImage'. Plain elf/32 kernel can't + be booted (plain vmlinux will not work). Similarly, existing initial ramdisks can + be used without modifications. + +XIII/ Booting on EFI/x86_64 platforms + ----------------------------- + + To use elilo on x86_64, you can put it on a floppy and + on a FAT32 partition (msdos partition). You can also + netboot if your network adapter has support for UNDI/PXE. + + Elilo/x86_64 requires efi64 enabled linux kernel (> 2.6.21). + You need to compile the kernel with CONFIG_EFI option. + x86_64 platforms with UEFI 2.0 firmware deprecate UGA protocol + and therefore only the Graphics Output Protocol (GOP) is supported. For + such platforms, the kernel must be configured with EFI_FB option. This + will enable early boot messages on the console. The elilo for x86_64 + attempts to query the firmware for GOP and if it fails it defaults to + text mode. Elilo ONLY takes compressed kernel image which are + typically obtained via a 'make bzImage'. Plain elf/x86_64 kernel can't + be booted (plain vmlinux will not work). Similarly, existing initial + ramdisks can be used without modifications. + + The x86_64 implementation converts the EFI memory map into E820 map and + passes it in the bootparameter supplied to the OS. For details on + bootparameter, see x86_64/sysdeps.h. + +IX/ Credits + ------- + + Contributors: + Intel Corp. + Stephane Eranian + David Mosberger + Johannes Erdfelt + Richard Hirst + Chris Ahna + Mike Johnston + Fenghua Yu + Bibo Mao + Brett Johnson + Jason Fleischli + Chandramouli Narayanan + + Maintainers: + Jason Fleischli + +X/ Bug reports + ----------- + + Use the sourceforge bug submission system on the elilo sourceforge + project page for reporting including errors or descrepancies in this + document. + +XIII/ Reference + --------- + + UEFI 2.0 specifications are available from the following web site: + + http://www.uefi.org/home + + EFI v1.02 specifications are available from the following web site: + + http://developer.intel.com/technology/efi/ + + The latest sources of ELILO can be downloaded at: + + https://sourceforge.net/projects/elilo/files/ + diff --git a/docs/elilo.txt b/docs/elilo.txt index 3de7501..a3fcc69 100644 --- a/docs/elilo.txt +++ b/docs/elilo.txt @@ -6,7 +6,7 @@ August 2003 - Copyright (C) 2000-2003 Hewlett-Packard Co. + Copyright (C) 2000-2012 Hewlett-Packard Co. Copyright (C) 2006-2010 Intel Co. @@ -14,7 +14,7 @@ I/ Introduction ------------ This document describes how to use ELILO on for IA-64, IA-32 and x86_64 EFI-based platforms. -This document describes ELILO version 3.7. +This document describes ELILO version 3.7 - 3.14. II/ Command line options -------------------- @@ -85,7 +85,7 @@ II/ Command line options For x86_64: ---------- - No new options. + none III/ Configuration File ------------------ @@ -243,7 +243,7 @@ III/ Configuration File x86_64 specific options: ----------------------- - None yet. + text-mode elilo>=3.14 boolean, image config option to force text console mode. IV/ Booting from the local system ----------------------------- @@ -481,6 +481,7 @@ XIII/ Booting on EFI/x86_64 platforms IX/ Credits ------- + Contributors: Intel Corp. Stephane Eranian David Mosberger @@ -490,14 +491,19 @@ IX/ Credits Mike Johnston Fenghua Yu Bibo Mao + Brett Johnson + Jason Fleischli Chandramouli Narayanan + + Maintainers: + Jason Fleischli X/ Bug reports ----------- - You can submit bugs to or to the Linux/ia64 - mailing list at linux-ia64@linuxia64.org. Visit http://www.linuxia64.org - to subscribe to this list. + Use the sourceforge bug submission system on the elilo sourceforge + project page for reporting including errors or descrepancies in this + document. XIII/ Reference --------- @@ -512,5 +518,5 @@ XIII/ Reference The latest sources of ELILO can be downloaded at: - ftp://ftp.hpl.hp.com/pub/linux-ia64 + https://sourceforge.net/projects/elilo/files/ diff --git a/elilo-ia32.efi b/elilo-ia32.efi old mode 100644 new mode 100755 index eb8d00b..431f2b4 Binary files a/elilo-ia32.efi and b/elilo-ia32.efi differ diff --git a/elilo-ia64.efi b/elilo-ia64.efi old mode 100644 new mode 100755 index 06b6e90..0004e55 Binary files a/elilo-ia64.efi and b/elilo-ia64.efi differ diff --git a/elilo-x86_64.efi b/elilo-x86_64.efi old mode 100644 new mode 100755 index c00be45..3dc8295 Binary files a/elilo-x86_64.efi and b/elilo-x86_64.efi differ diff --git a/elilo.c b/elilo.c index 31c7294..34835f9 100644 --- a/elilo.c +++ b/elilo.c @@ -46,7 +46,7 @@ #include "loader.h" #include "config.h" /* for config_init() */ -#define ELILO_SHARED_CMDLINE_OPTS L"pPMC:aDhd:i:vVc:E" +#define ELILO_SHARED_CMDLINE_OPTS L"pPMC:aDhd:i:m:vVc:E" elilo_config_t elilo_opt; @@ -93,7 +93,7 @@ do_kernel_load(CHAR16 *kname, kdesc_t *kd) INTN kernel_load(EFI_HANDLE image, CHAR16 *kname, kdesc_t *kd, memdesc_t *imem, memdesc_t *mmem) { - CHAR16 kernel[CMDLINE_MAXLEN]; + CHAR16 kernel[FILENAME_MAXLEN]; /* * Do the vm image switch here @@ -240,7 +240,7 @@ main_loop(EFI_HANDLE dev, CHAR16 **argv, INTN argc, INTN index, EFI_HANDLE image } do_launch: - r =subst_vars(cmdline_tmp, cmdline, CMDLINE_MAXLEN); + r = subst_vars(cmdline_tmp, cmdline, CMDLINE_MAXLEN); VERB_PRT(3, Print(L"final cmdline(%d): %s\n", r, cmdline)); @@ -481,7 +481,12 @@ efi_main (EFI_HANDLE image, EFI_SYSTEM_TABLE *system_tab) * mode. * XXX: clean this up ! */ - uefi_call_wrapper(BS->SetWatchdogTimer, 4, 0, 0x0, 0, NULL); + uefi_call_wrapper(BS->SetWatchdogTimer, 4, 0, 0x0, 0, NULL); + + /* + * start a clean console + */ + uefi_call_wrapper(systab->ConOut->Reset, 2, systab->ConOut, FALSE); /* initialize memory allocator */ if (alloc_init() == -1) return EFI_LOAD_ERROR; diff --git a/elilo.h b/elilo.h index 4809fbe..041ff1e 100644 --- a/elilo.h +++ b/elilo.h @@ -29,7 +29,7 @@ #ifndef __ELILO_H__ #define __ELILO_H__ -#define ELILO_VERSION L"3.12" +#define ELILO_VERSION L"3.16" #include @@ -54,6 +54,10 @@ #define ROUNDUP(x,a) (((x) + (a) - 1) & ~((a) - 1)) #define ROUNDDOWN(x,a) ((x) & ~((a) - 1)) +#ifndef UINT32_MAX +#define UINT32_MAX ((UINT32)-1) +#endif + /* * Elilo Boot modes */ @@ -65,7 +69,8 @@ #define ELILO_DEFAULT_TIMEOUT ELILO_TIMEOUT_INFINITY #define ELILO_TIMEOUT_INFINITY (~0UL) -#define CMDLINE_MAXLEN 512 /* needed by ia32 */ +#define CMDLINE_MAXLEN 2048 +#define PATHNAME_MAXLEN 512 #define FILENAME_MAXLEN 256 #define MAX_ARGS 256 /* Just pick an arbitrary number that's high enough for now :o) */ @@ -212,6 +217,7 @@ extern CHAR16 *sysdeps_get_cmdline_opts(VOID); extern INTN sysdeps_getopt(INTN, INTN, CHAR16 *); extern VOID sysdeps_print_cmdline_opts(VOID); extern INTN sysdeps_register_options(VOID); +extern VOID *sysdeps_checkfix_initrd(VOID *, memdesc_t *); #define CHAR_SLASH L'/' #define CHAR_BACKSLASH L'\\' diff --git a/fileops.c b/fileops.c index 1a43479..9cf66eb 100644 --- a/fileops.c +++ b/fileops.c @@ -497,7 +497,7 @@ add_dev_tab(EFI_GUID *proto, EFI_HANDLE boot_handle, UINTN size, fops_fs_glue_t str2 = str == NULL ? L"Unknown" : str; - DBG_PRT((L"%s : %-8s : %s\n", dev_tab[idx].name, + DBG_PRT((L"%s : %-8s : %s", dev_tab[idx].name, (dev_tab[idx].fops ? dev_tab[idx].fops->name: L"N/A"), str2)); if (str) FreePool(str); diff --git a/fs/Makefile b/fs/Makefile index 1829d96..0bb303f 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -23,10 +23,15 @@ # to use this program. # -include ../Make.defaults -include ../Make.rules +SRCDIR = . + +VPATH = $(SRCDIR) + +include $(SRCDIR)/../Make.defaults +include $(SRCDIR)/../Make.rules + +TOPDIR=$(SRCDIR)/.. -TOPDIR=$(CDIR)/.. FILES= ifeq ($(CONFIG_localfs),y) @@ -54,17 +59,13 @@ all: $(TARGET) # XXX: does not trigger recompile when changing filesystem selection # without doing make clean. # -$(TARGET): check-filesystems $(TOPDIR)/Make.defaults $(FILES) - $(LD) -r -o $@ $(FILES) +$(TARGET): $(TOPDIR)/Make.defaults $(FILES) + @if [ -z "$(FILES)" ]; then \ + echo "You need to define at least one filesystem in Make.defaults"; \ + exit 1; \ + fi + $(LD) $(LD3264) -r -o $@ $(FILES) clean: $(RM) -f $(TARGET) $(FILES) -check-filesystems: - @if [ -n "$(FILES)" ]; then \ - exit 0; \ - else \ - echo "You need to define at least one filesystem in Make.defaults"; \ - exit 1; \ - fi - diff --git a/fs/localfs.c b/fs/localfs.c index fe1333f..7f09ab1 100644 --- a/fs/localfs.c +++ b/fs/localfs.c @@ -98,7 +98,7 @@ localfs_open(localfs_interface_t *this, CHAR16 *name, UINTN *fd) DBG_PRT((L"localfs_open on %s\n", name)); - status = uefi_call_wrapper(lfs->volume->Open, 5, lfs->volume, &fh, name, EFI_FILE_MODE_READ, 0); + status = uefi_call_wrapper(lfs->volume->Open, 5, lfs->volume, &fh, name, EFI_FILE_MODE_READ, (UINT64)0); if (status == EFI_SUCCESS) { *fd = LOCALFS_F2FD(fh); } diff --git a/glue_netfs.c b/glue_netfs.c index e47bcc8..eebfecc 100644 --- a/glue_netfs.c +++ b/glue_netfs.c @@ -64,6 +64,19 @@ static CHAR16 netfs_default_path[FILENAME_MAXLEN]; static CHAR16 *hexa=L"0123456789ABCDEF"; +static VOID +convert_mac2hex(UINT8 *hw_addr,INTN l, CHAR16 *str) +{ + UINTN i; + + for (i=0 ; i < l; i++) { + str[3*i] = hexa[(hw_addr[i] & 0xf0)>>4]; + str[3*i+1] = hexa[hw_addr[i] & 0x0f]; + str[3*i+2] = ':'; + } + str[3*l-1]='\0'; +} + static VOID convert_ip2hex(UINT8 *ip, INTN l, CHAR16 *str) { @@ -153,6 +166,8 @@ netfs_setdefaults(VOID *intf, config_file_t *config, CHAR16 *kname, UINTN maxlen set_var(VAR_NETFS_DOMAINAME, info.domainame); if (info.using_pxe) { + DBG_PRT((L"netfs_setdefaults: using_pxe")); + status = netfs->netfs_query_layer(netfs, 0, NETFS_CONFIG_LAYER, maxlen, config[0].fname); if (EFI_ERROR(status)) { StrnCpy(config[0].fname, NETFS_DEFAULT_CONFIG, maxlen-1); @@ -181,6 +196,8 @@ netfs_setdefaults(VOID *intf, config_file_t *config, CHAR16 *kname, UINTN maxlen # endif # define CONFIG_EXTENSION L".conf\0" + + DBG_PRT((L"netfs_setdefaults: machine specific (!using_pxe)")); /* * will try machine/subnet specific files first. * the filenames are constructed based on the IP(v4) address @@ -206,6 +223,12 @@ netfs_setdefaults(VOID *intf, config_file_t *config, CHAR16 *kname, UINTN maxlen StrnCpy(config[6].fname, str, maxlen-1); StrnCpy(config[6].fname+2, CONFIG_EXTENSION, 6); + + /* use the MAC address as a possible file name as well */ + convert_mac2hex(info.hw_addr,6,str); + StrnCpy(config[7].fname, str, maxlen-1); + StrnCpy(config[7].fname+17, CONFIG_EXTENSION, 6); + #else StrnCpy(config[0].fname, NETFS_DEFAULT_CONFIG, maxlen-1); config[0].fname[maxlen-1] = CHAR_NULL; diff --git a/ia32/Makefile b/ia32/Makefile index 353ae67..c5f421b 100644 --- a/ia32/Makefile +++ b/ia32/Makefile @@ -23,10 +23,15 @@ # to use this program. # -include ../Make.defaults -include ../Make.rules +SRCDIR = . + +VPATH = $(SRCDIR) + +include $(SRCDIR)/../Make.defaults +include $(SRCDIR)/../Make.rules + +TOPDIR=$(SRCDIR)/.. -TOPDIR=$(CDIR)/.. FILES=system.o config.o bzimage.o plain_loader.o gzip_loader.o gzip.o @@ -37,13 +42,13 @@ all: $(TARGET) system.o: rmswitch.h rmswitch.h: bin_to_h.c rmswitch.S - $(CC) -o bin_to_h bin_to_h.c - $(AS) -o rmswitch.o rmswitch.S + $(CC) -o bin_to_h $(SRCDIR)/bin_to_h.c + $(AS) -o rmswitch.o $(SRCDIR)/rmswitch.S $(LD) -Ttext 0x0 -s --oformat binary -o rmswitch rmswitch.o ./bin_to_h rmswitch.h $(TARGET): $(FILES) - $(LD) -r -o $@ $(FILES) + $(LD) $(LD3264) -r -o $@ $(FILES) clean: $(RM) -f $(TARGET) $(FILES) diff --git a/ia32/bzimage.c b/ia32/bzimage.c index 6e4e056..bb00632 100644 --- a/ia32/bzimage.c +++ b/ia32/bzimage.c @@ -169,7 +169,7 @@ bzImage_probe(CHAR16 *kname) kernel_start)); } - kernel_load_address = kernel_start; + kernel_load_address = NULL; /* allocate anywhere! */ if (alloc_kmem(kernel_start, EFI_SIZE_TO_PAGES(kernel_size)) != 0) { /* diff --git a/ia32/system.c b/ia32/system.c index 078d406..876b68c 100644 --- a/ia32/system.c +++ b/ia32/system.c @@ -149,6 +149,12 @@ sysdeps_initrd_get_addr(kdesc_t *kd, memdesc_t *imem) return 0; } +VOID * +sysdeps_checkfix_initrd(VOID *start_addr, memdesc_t *imem) +{ + return start_addr; +} + VOID sysdeps_free_boot_params(boot_params_t *bp) { @@ -201,7 +207,8 @@ static INTN get_video_info(boot_params_t * bp) { (VOID **)Gop_handle); if (EFI_ERROR(efi_status) && efi_status != EFI_BUFFER_TOO_SMALL) { - ERR_PRT((L"LocateHandle GopProtocol failed.")); + Print(L"EFI returned no GoP handle, No Graphics Output Device?\n"); + Print(L"--Elilo will try to default to console text mode.\n"); return -1; } Gop_handle = alloc(size, 0); @@ -470,9 +477,6 @@ sysdeps_create_boot_params( */ if (param_start != NULL) { CopyMem(bp, param_start, 0x2000); - free(param_start); - param_start = NULL; - param_size = 0; } /* * Save off our header revision information. diff --git a/ia64/Makefile b/ia64/Makefile index a243d0f..bee0a2b 100644 --- a/ia64/Makefile +++ b/ia64/Makefile @@ -23,10 +23,15 @@ # to use this program. # -include ../Make.defaults -include ../Make.rules +SRCDIR = . + +VPATH = $(SRCDIR) + +include $(SRCDIR)/../Make.defaults +include $(SRCDIR)/../Make.rules + +TOPDIR=$(SRCDIR)/.. -TOPDIR=$(CDIR)/.. FILES=system.o config.o fpswa.o plain_loader.o gzip_loader.o \ gzip.o memset.o memcpy.o setjmp.o longjmp.o diff --git a/ia64/system.c b/ia64/system.c index 2530a3b..2f4223d 100644 --- a/ia64/system.c +++ b/ia64/system.c @@ -140,6 +140,12 @@ sysdeps_initrd_get_addr(kdesc_t *kd, memdesc_t *imem) return 0; } +VOID * +sysdeps_checkfix_initrd(VOID *start_addr, memdesc_t *imem) +{ + return start_addr; +} + /* Flush data cache [addr; addr + len], and sync with icache. */ void flush_dcache (CHAR8 *addr, UINT64 len) diff --git a/initrd.c b/initrd.c index 581abda..7a68bb3 100644 --- a/initrd.c +++ b/initrd.c @@ -41,7 +41,11 @@ INTN load_file(CHAR16 *filename, memdesc_t *image) { EFI_STATUS status; - VOID *start_addr = NULL; + /* + * Actually using the value from sysdeps_initrd_get_addr() + * instead of NULL is no change for ia64! + */ + VOID *start_addr = image->start_addr; UINTN pgcnt; UINT64 size = 0; fops_fd_t fd; @@ -71,7 +75,11 @@ load_file(CHAR16 *filename, memdesc_t *image) /* 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, 0 ); + start_addr = alloc_pages(pgcnt, EfiLoaderData, + start_addr ? AllocateAddress : AllocateAnyPages, start_addr); + + start_addr = sysdeps_checkfix_initrd(start_addr, image); + if (start_addr == NULL) { ERR_PRT((L"Failed to allocate %d pages for %s image", pgcnt, filename)); diff --git a/release.notes b/release.notes index 725c6e2..411f047 100644 --- a/release.notes +++ b/release.notes @@ -1,53 +1,72 @@ -3 . 1 2 R E L E A S E N O T E S +3 . 1 6 R E L E A S E N O T E S =================================== -QUICK SUMMARY +QUICK CHANGE SUMMARY ==================== -* FIXES MAC CONSOLE ISSUE -* FIXES NETBOOT BROKEN -* FIXES EXITBOOTSERVICES FAILURE -* TEMP FIX INCREASE BZIMAGE LIMITS - + * Adds native x86x crossbuild functionality + build 32bit or 64bit versions from either environment via + make ARCH=ia32|x86_64 (the ARCH IS case sensitive). + make by itself will default to the native host arch. + * Add console reset call during initialization. thanks A. Steinmetz + * simplify output of no GOP warning text so it no longer looks like an error. + * MAJOR: Fixed Fault crash when EFI memory map changes from under elilo. + (from an outside interrupt in this case). When the EFI Memory map + changes after elilo has already built boot params to pass to the + kernel the EFI call to ExitBootSvcs just prior to boot will fail + because elilo has the old map key. This is valid EFI behavior, elilo + retries to pick up the new memory map and key but had already freed + the start params portion of boot params resulting in a NULL DEREF + crash reset once it hands the now bogus boot params to the kernel on + the 2nd successful call to exit efi and boot. + Thanks to Jerry Hoemann @ HP for reporting this bug. + * minor bugfix, fixed -m option broken. thanks Allan-lsk. + BUILD NOTES ==================== - You will need the following toolchain to build elilo-3.12 from source + You will need the following toolchain to build elilo-3.14 from source the elilo build environment is optimized for Debian and Debian based distros. - 1. gnu-efi3.0d or greater, (you will want gnu-efi3.0i or > for cross build env - setups) elilo-3.12 binaries were built with gnu-efi3.0e-2 - 2. gcc-4.1.1 or greater, elilo-3.12 binaries were built with: - x86 -> 4.2.3-1ubuntu6 - x86_64 -> 4.2.3-1ubuntu6 - ia64 -> 4.3.2-1.1 - 3. binutils-2.17.50.0.14 or greater, elilo-3.12 binaries were built with: - x86 -> 2.18.1-cvs20080103-0ubuntu1 - x86_64 -> 2.18.1~cvs20080103-0ubuntu1 - ia64 -> 2.18.1~cvs20080103-7 - - * if you use a debian based (lenny)build environment you will have no problems + elilo-3.16 was built in the squeeze+(ubuntu 11.x) build environments except + for itanium which is unchanged to best support legacy enterprise configs. + Toolchain versions for this release were: + x86x(32 & 64bit versions) + * gnu-efi --> 3.0i-3 + * gcc ------> 4:4.4.4-1ubuntu2 + * binutils -> 2.20.51.20100908-0ubuntu2 + ia64 + * gnu-efi --> 3.0e-2 + * gcc ------> 4.3.2-2 + * binutils -> 2.18.1~cvs20080103-7 + + * if you use a debian based build environment you will have no problems and setting it up is simple. you will be able to build elilo in 3 steps: 1. apt-get install gnu-efi, gcc, binutils - 2. apt-get source elilo (or download elilo-3.12.tar.gz from SourceForge.) - 3. cd ./elilo-3.12 and type make + 2. apt-get source elilo (or download elilo-3.16 source from SourceForge.) + 3. extract source tarball and cd to ./$your-elilo-source and type $> make - ** If you use the upstream tarballs for the toolchain you will need to move - some files around. + + ** If you use the upstream toolchain tarballs(i.e. pre distro) you will need + to move some files around for elilo build to work. GNU-EFI (provides the efi 1.10 and uefi 2.x libraries & api) ------- gnu-efi libraries are installed to /usr/local/lib by the upstream gnu-efi source package. elilo expects them to be in system location /usr/lib. efi includes may be located in /usr/local/include/efi. elilo expects them to be in system location /usr/include/efi. + [ The reason is LSB compliance ]. BINUTILS (provides the elf conversion utility to produce efi bins) -------- - likewise objcopy may be installed to /usr/local/bin by binutils, + binutils provides objcopy which is installed to /usr/local/bin by binutils, elilo source expects it to be in /usr/bin. + again this LSB compliance is taken care of by the distro's that fix + the toolchains to install to the correct compliant system locations + instead of the "user optional" location. ELILO ON EFI X86_64 ===================== HARD REQUIREMENTS - EFI + x86_64 requires efi64 enabled linux kernel i.e. 2.6.21 or newer + EFI + x86_64 REQUIRES an efi64 enabled linux kernel i.e. 2.6.21 or newer nothing earlier will work, 2.6.21 was the earliest kernel that efi64 support went into. You need to compile the kernel with CONFIG_EFI kernel option ON. @@ -57,12 +76,34 @@ HARD REQUIREMENTS will enable early boot messages on the console. Elilo for x86_64 attempts to query EFI for GOP support and if it fails it defaults to text mode which may or may not show you early console ouput depends on - your efi and physical setup. + your efi console settings and physical setup. Elilo has no way to know + if your console settings are messed up. WORKING ELILO.CONF FOR EFI X86_64 EXAMPLE Here is my elilo.conf from my UEFI2.0/x86_64 (with nvidia pcie add on card, i.e. your vga= kernel param may be different) workstation which uses GOP. - ...shows me console output, what elilo is doing, and kernel boot. + Here is a partial kernel vga table I was able to find and add here. +Colours 640x400 640x480 800x600 1024x768 1152x864 1280x1024 1600x1200 + -------+-------------------------------------------------------------- + 4 bits | ? ? 0x302 ? ? ? ? + 8 bits | 0x300 0x301 0x303 0x305 0x161 0x307 0x31C + 15 bits | ? 0x310 0x313 0x316 0x162 0x319 0x31D + 16 bits | ? 0x311 0x314 0x317 0x163 0x31A 0x31E + decimal | d785 d788 d791 + 24 bits | ? 0x312 0x315 0x318 ? 0x31B 0x31F + +Additionally from ...kernel-source/Documentation/Boot.txt... + vga= + here is either an integer (in C notation, either + decimal, octal, or hexadecimal) or one of the strings + "normal" (meaning 0xFFFF), "ext" (meaning 0xFFFE) or "ask" + (meaning 0xFFFD). This value should be entered into the + vid_mode field, as it is used by the kernel before the command + line is parsed. + + example below shows me console output, what elilo is doing, and kernel boot. + vga=normal with efi console input output directed to graphics card should + work as well. default=UBUNTU chooser=simple @@ -70,35 +111,9 @@ WORKING ELILO.CONF FOR EFI X86_64 EXAMPLE delay=30 append="root=/dev/sda3 vga=0x31e splash showopts" - image=/vmlinuz-2.6.24-23-generic + image=/vmlinuz-2.6.32-27-generic label="UBUNTU" - description="Ubuntu 2.6.24-23-generic kernel" - initrd=/initrd.img-2.6.24-23-generic + description="Ubuntu 2.6.32-27-generic kernel" + initrd=/initrd.img-2.6.32-27-generic -CHANGES FROM 3.10 TO 3.12 -======================== -Patch contributions from Julen Blache @ Debian -thank you. ** ADDS MAC IA32 NATIVE BOOT SUPPORT (i.e. consplitter fix) - - * Added additional #defines for debug levels to reduce the output noise - * Added Mac console patch rework from Julien Blache @ debian - this fixes the invisible console output from elilo on Macs - * Moved static ELILO_VERSION variable from elilo.c to elilo.h - so that elilo will print its version string and arch on startup. - * Fixed bug 2825044 ExitBootServices error handling, correctly deal - with changed memory map key if memory map changes from under elilo. - * Added memory map key to map debug output. - * Fixed bug 2874380 netbooting just flat broken. fixed ia64, x86_64 - ia32, fixed handling of server side support of tfpt options (get file size) - elilo now attempts to get file size before attempting read of file - to set the buffers up correctly and deal with tftp servers that dont - support options extensions a little better. - * netboot, fixed bad blocksize handling - * netboot, fixed filename length for elilo-x86_64.conf type on tftp - server. - * increased bzimage kernel max length sizes to 4mb on i386 and 8mb on - x86_64... this is a legacy design hold over from original design and - needs to be re-written to do dynamic size memory management based on - the size of the actual vmlinuz image, as ia64/gzip does. - diff --git a/strops.c b/strops.c index b47a58e..98a66a4 100644 --- a/strops.c +++ b/strops.c @@ -41,11 +41,11 @@ StrnCpy(OUT CHAR16 *dst, IN const CHAR16 *src, IN UINTN size) { CHAR16 *res = dst; - while (size-- && (*dst++ = *src++) != CHAR_NULL); + while (size && size-- && (*dst++ = *src++) != CHAR_NULL); /* * does the null padding */ - while (size-- > 0) *dst++ = CHAR_NULL; + while (size && size-- > 0) *dst++ = CHAR_NULL; return res; } @@ -55,11 +55,11 @@ StrnXCpy(OUT CHAR8 *dst, IN const CHAR16 *src, IN UINTN size) { CHAR8 *res = dst; - while (size-- && (*dst++ = (CHAR8)*src++) != '\0'); + while (size && size-- && (*dst++ = (CHAR8)*src++) != '\0'); /* * does the null padding */ - while (size-- > 0) *dst++ = '\0'; + while (size && size-- > 0) *dst++ = '\0'; return res; } @@ -76,11 +76,11 @@ strncpya(OUT CHAR8 *dst, IN const CHAR8 *src, IN UINTN size) { CHAR8 *res = dst; - while (size-- && (*dst++ = *src++) != '\0'); + while (size && size-- && (*dst++ = *src++) != '\0'); /* * does the null padding */ - while (size-- > 0) *dst++ = '\0'; + while (size && size-- > 0) *dst++ = '\0'; return res; } diff --git a/tools/Makefile b/tools/Makefile index 8858224..97083d7 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -23,10 +23,15 @@ # to use this program. # -include ../Make.defaults -include ../Make.rules +SRCDIR = . + +VPATH = $(SRCDIR) + +include $(SRCDIR)/../Make.defaults +include $(SRCDIR)/../Make.rules + +TOPDIR=$(SRCDIR)/.. -TOPDIR=$(CDIR)/.. FILES=eliloalt.o TARGET=eliloalt diff --git a/tools/eliloalt.c b/tools/eliloalt.c index 1c9709a..8af2bf2 100644 --- a/tools/eliloalt.c +++ b/tools/eliloalt.c @@ -47,8 +47,10 @@ #define ELILOALT_VERSION "0.02" #define ELILO_ALT_NAME "EliloAlt" -#define EFIVAR_DIR "/proc/efi/vars" +#define EFIVAR_DIR "/sys/firmware/efi/vars" +#define OFIVAR_DIR "/proc/efi/vars" #define ELILO_ALTVAR EFIVAR_DIR"/"ELILO_ALT_NAME"-00000000-0000-0000-0000-000000000000" +#define OLILO_ALTVAR OFIVAR_DIR"/"ELILO_ALT_NAME"-00000000-0000-0000-0000-000000000000" #define EFI_VARIABLE_NON_VOLATILE 0x0000000000000001 #define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x0000000000000002 @@ -80,7 +82,9 @@ typedef struct _efi_variable_t { uint32_t attributes; } __attribute__((packed)) efi_variable_t; +static char *efivar_dir = EFIVAR_DIR; static char *elilo_alt_name = ELILO_ALT_NAME; +static char *elilo_altvar = ELILO_ALTVAR; static struct option cmd_options[]={ { "version", 0, 0, 1}, @@ -129,9 +133,15 @@ check_proc_efi(int find_entry) if (getuid() != 0) { fatal_error("This program must be run as root\n"); } - efi_vars = opendir(EFIVAR_DIR); + efi_vars = opendir(efivar_dir); if (efi_vars == NULL) { - fatal_error("Cannot access %s\n", EFIVAR_DIR); + efivar_dir = OFIVAR_DIR; + elilo_altvar = OLILO_ALTVAR; + efi_vars = opendir(efivar_dir); + } + if (efi_vars == NULL) { + fatal_error("Can access neither %s nor %s\n", + EFIVAR_DIR, efivar_dir); } if (!find_entry) { closedir(efi_vars); @@ -143,9 +153,10 @@ check_proc_efi(int find_entry) break; } if (entry == NULL) { - fatal_error("Cannot find entry in %s\n", EFIVAR_DIR); + fatal_error("Cannot find entry in %s\n", efivar_dir); } - sprintf(name, "%s/%s", EFIVAR_DIR, entry->d_name); + snprintf(name, 1023, "%s/%s", efivar_dir, entry->d_name); + name[1023] = 0; closedir(efi_vars); return name; } @@ -158,7 +169,7 @@ delete_var(void) check_proc_efi(0); - fd = open(ELILO_ALTVAR, O_WRONLY); + fd = open(elilo_altvar, O_WRONLY); if (fd == -1) { fatal_error("variable not defined\n"); } @@ -176,7 +187,7 @@ delete_var(void) r = write(fd, &var, sizeof(var)); if (r != sizeof(var)) { - fatal_error("Variable %s defined but invalid content\n", ELILO_ALTVAR); + fatal_error("Variable %s defined but invalid content\n", elilo_altvar); } close(fd); } @@ -191,7 +202,7 @@ print_var(void) check_proc_efi(0); - fd = open(ELILO_ALTVAR, O_RDONLY); + fd = open(elilo_altvar, O_RDONLY); if (fd == -1) { fatal_error("variable not defined\n"); } @@ -200,7 +211,7 @@ print_var(void) r = read(fd, &var, sizeof(var)); if (r != sizeof(var)) { - fatal_error("Variable %s defined but invalid content\n", ELILO_ALTVAR); + fatal_error("Variable %s defined but invalid content\n", elilo_altvar); } printf("EliloAlt=\""); for(i=0; i < var.datasize; i+=1){ @@ -231,7 +242,7 @@ set_var(char *cmdline) fd = open(name, O_WRONLY); if (fd == -1) { - fatal_error("can't open %s: %s\n", ELILO_ALTVAR, strerror(errno)); + fatal_error("can't open %s: %s\n", elilo_altvar, strerror(errno)); } memset(&var, 0, sizeof(var)); @@ -256,7 +267,7 @@ set_var(char *cmdline) r = write(fd, &var, sizeof(var)); if (r != sizeof(var)) { - fatal_error("Variable %s defined but invalid content %d\n", ELILO_ALTVAR, r); + fatal_error("Variable %s defined but invalid content %d\n", elilo_altvar, r); } close(fd); diff --git a/x86_64/Makefile b/x86_64/Makefile index 4af4b8d..7ade312 100644 --- a/x86_64/Makefile +++ b/x86_64/Makefile @@ -23,10 +23,15 @@ # to use this program. # -include ../Make.defaults -include ../Make.rules +SRCDIR = . + +VPATH = $(SRCDIR) + +include $(SRCDIR)/../Make.defaults +include $(SRCDIR)/../Make.rules + +TOPDIR=$(SRCDIR)/.. -TOPDIR=$(CDIR)/.. FILES=system.o config.o bzimage.o plain_loader.o gzip_loader.o gzip.o #FILES=system.o config.o plain_loader.o @@ -38,13 +43,13 @@ all: $(TARGET) system.o: rmswitch.h rmswitch.h: bin_to_h.c rmswitch.S - $(CC) -o bin_to_h bin_to_h.c - $(AS) -o rmswitch.o rmswitch.S + $(CC) -o bin_to_h $(SRCDIR)/bin_to_h.c + $(AS) -o rmswitch.o $(SRCDIR)/rmswitch.S $(LD) -Ttext 0x0 -s --oformat binary -o rmswitch rmswitch.o ./bin_to_h rmswitch.h $(TARGET): $(FILES) - $(LD) -r -o $@ $(FILES) + $(LD) $(LD3264) -r -o $@ $(FILES) clean: $(RM) -f $(TARGET) $(FILES) diff --git a/x86_64/bzimage.c b/x86_64/bzimage.c index e3c7c6b..9be4bd6 100644 --- a/x86_64/bzimage.c +++ b/x86_64/bzimage.c @@ -36,6 +36,129 @@ UINTN param_size = 0; UINTN kernel_size = 0x800000; /* 8M (default x86_64 bzImage size limit) */ +static VOID * +bzImage_alloc() +{ + UINTN pages = EFI_SIZE_TO_PAGES(kernel_size); + int reloc_kernel = 0; + VOID *kla, *kend = kernel_start + kernel_size; + UINT32 kalign, kmask; + boot_params_t *ps = param_start; + + /* + * Get address for kernel from header, if applicable & available. + */ + if ((ps->s.hdr_major < 2) || + (ps->s.hdr_major == 2 && ps->s.hdr_minor < 5)) { + reloc_kernel = 0; + } else { + if (ps->s.kernel_start >= DEFAULT_KERNEL_START) + kernel_start = (void *)(UINT64)ps->s.kernel_start; + reloc_kernel = ps->s.relocatable_kernel; + kalign = ps->s.kernel_alignment; + kmask = kalign - 1; + VERB_PRT(3, Print(L"kernel header (%d.%d) suggests kernel " + "start at address "PTR_FMT" (%srelocatable!)\n", + ps->s.hdr_major, ps->s.hdr_minor, ps->s.kernel_start, + (reloc_kernel ? L"": L"not "))); + } + + /* + * Best effort for old (< 2.6.20) and non-relocatable kernels + */ + if (alloc_kmem(kernel_start, pages) == 0) { + VERB_PRT(3, Print(L"kernel_start: "PTR_FMT" kernel_size: %d\n", + kernel_start, kernel_size)); + return kernel_start; + } else if ( ! reloc_kernel ) { + /* + * Couldn't get desired address--just load it anywhere and + * (try to) move it later. It's the only chance for non- + * relocatable kernels, but it breaks occassionally... + */ + ERR_PRT((L"Kernel header (%d.%d) suggests kernel " + "start at address "PTR_FMT" (non relocatable!)\n" + "This address is not available, so an attempt" + "is made to copy the kernel there later on\n" + "BEWARE: this is unsupported and may not work. " + "Please update your kernel.\n", + ps->s.hdr_major, ps->s.hdr_minor, ps->s.kernel_start)); + kla = (VOID *)(UINT32_MAX - kernel_size); + /* NULL would preserve the "anywhere" semantic, */ + /* but it would not prevent allocation above 4GB! */ + + if (alloc_kmem_anywhere(&kla, pages) != 0) { + /* out of luck */ + return NULL; + } + VERB_PRT(3, Print(L"kernel_start: "PTR_FMT + " kernel_size: %d loading at: "PTR_FMT"\n", + kernel_start, kernel_size, kla)); + return kla; + } + + + /* Is 'ps->s.kernel_alignment' guaranteed to be sane? */ + if (kalign < EFI_PAGE_SIZE) { + kalign = EFI_PAGE_SIZE; + kmask = EFI_PAGE_MASK; + } + DBG_PRT((L"alignment: kernel=0x%x efi_page=0x%x : 0x%x\n", + ps->s.kernel_alignment, EFI_PAGE_SIZE, kalign)); + + /* + * Couldn't get the preferred address, but luckily it's + * a relocatable kernel, so ... + * + * 1. use 'find_kernel_memory()' (like Itanium) + * 2. try out the 16 lowest possible aligned addresses (> 0) + * 3. get enough memory to align "creatively" + * 4. forget alignment (and start praying)... + */ + + /* 1. */ + if ((find_kernel_memory(kernel_start, kend, kalign, &kla) != 0) || + (alloc_kmem(kla, pages) != 0)) { + kla = NULL; + } + + /* 2. */ + if ( ! kla && (UINT64)kernel_start < kalign ) { + int i; + for ( i = 1; i < 16 && !kla; i++ ) { + VOID *tmp = (VOID *)((UINT64)kalign * i); + if (alloc_kmem(tmp, pages) == 0) { + kla = tmp; + } + } + } + + /* 3. */ + if ( ! kla ) { + UINTN apages = EFI_SIZE_TO_PAGES(kernel_size + kmask); + kla = (VOID *)(UINT32_MAX - kernel_size - kmask); + + if (alloc_kmem_anywhere(&kla, apages) == 0) { + kla = (VOID *)(((UINT64)kla + kmask) & ~kmask); + } else { + kla = NULL; + } + } + + /* 4. last resort */ + if ( ! kla ) { + kla = (VOID *)(UINT32_MAX - kernel_size); + if (alloc_kmem_anywhere(&kla, pages) != 0) { + return NULL; + } + } + + kernel_start = kla; + VERB_PRT(1, Print(L"relocating kernel_start: "PTR_FMT + " kernel_size: %d\n", kernel_start, kernel_size)); + return kla; +} + static INTN bzImage_probe(CHAR16 *kname) { @@ -158,53 +281,34 @@ bzImage_probe(CHAR16 *kname) * Allocate memory for kernel. */ - /* - * Get correct address for kernel from header, if applicable & available. - */ - if ((param_start->s.hdr_major == 2) && - (param_start->s.hdr_minor >= 6) && - (param_start->s.kernel_start >= DEFAULT_KERNEL_START)) { - kernel_start = (void *)param_start->s.kernel_start; - VERB_PRT(3, Print(L"kernel header suggests kernel start at address "PTR_FMT"\n", - kernel_start)); + kernel_load_address = bzImage_alloc(); + if ( ! kernel_load_address ) { + ERR_PRT((L"Could not allocate memory for kernel.")); + free(param_start); + param_start = NULL; + param_size = 0; + fops_close(fd); + return -1; } - kernel_load_address = kernel_start; - - if (alloc_kmem(kernel_start, EFI_SIZE_TO_PAGES(kernel_size)) != 0) { - /* - * Couldn't get desired address--just load it anywhere and move it later. - * (Easier than relocating kernel, and also works with non-relocatable kernels.) - */ - if (alloc_kmem_anywhere(&kernel_load_address, EFI_SIZE_TO_PAGES(kernel_size)) != 0) { - ERR_PRT((L"Could not allocate memory for kernel.")); - free(param_start); - param_start = NULL; - param_size = 0; - fops_close(fd); - return -1; - } - } - - VERB_PRT(3, Print(L"kernel_start: "PTR_FMT" kernel_size: %d loading at: "PTR_FMT"\n", - kernel_start, kernel_size, kernel_load_address)); - /* * Now read the rest of the kernel image into memory. */ - DBG_PRT((L"reading kernel image...\n")); + Print(L"Loading kernel %s... ", kname); size = kernel_size; efi_status = fops_read(fd, kernel_load_address, &size); if (EFI_ERROR(efi_status) || size < 0x10000) { - ERR_PRT((L"Error reading kernel image %s.", kname)); + ERR_PRT((L"Error reading kernel image (0x%x).", efi_status)); free(param_start); param_start = NULL; param_size = 0; fops_close(fd); free_kmem(); return -1; + } else { + Print(L" done\n"); } DBG_PRT((L"kernel image read: %d bytes, %d Kbytes\n", size, size / 1024)); diff --git a/x86_64/config.c b/x86_64/config.c index e8d4620..59e7b10 100644 --- a/x86_64/config.c +++ b/x86_64/config.c @@ -33,15 +33,23 @@ typedef struct { UINTN legacy_free_boot; + UINTN text_mode; } x86_64_global_config_t; +#define x86_64_opt_offsetof(option) (&((sys_img_options_t *)(0x0))->option) + static x86_64_global_config_t x86_64_gconf; static config_option_t sysdeps_global_options[]={ {OPT_BOOL, OPT_GLOBAL, L"legacy-free", NULL, NULL, &x86_64_gconf.legacy_free_boot} }; +static config_option_t sysdeps_image_options[]={ + {OPT_BOOL, OPT_IMAGE_SYS, L"text-mode", NULL, NULL, x86_64_opt_offsetof(text_mode)} +}; + + /* * X86_64 operations that need to be done only once and just before * entering the main loop of the loader @@ -81,6 +89,14 @@ x86_64_use_legacy_free_boot(VOID) return x86_64_gconf.legacy_free_boot ? 1 : 0; } + +INTN +x86_64_text_mode(VOID) +{ + return (elilo_opt.sys_img_opts && + elilo_opt.sys_img_opts->text_mode == TRUE) ? 1 : 0; +} + INTN sysdeps_register_options(VOID) { @@ -89,14 +105,11 @@ sysdeps_register_options(VOID) ret = register_config_options(sysdeps_global_options, sizeof(sysdeps_global_options)/sizeof(config_option_t), OPTIONS_GROUP_GLOBAL); -#if 0 - /* no per image options yet */ if (ret == -1 ) return ret; ret = register_config_options(sysdeps_image_options, sizeof(sysdeps_image_options)/sizeof(config_option_t), OPTIONS_GROUP_IMAGE); -#endif return ret; } diff --git a/x86_64/sysdeps.h b/x86_64/sysdeps.h index 338aa40..ff99eef 100644 --- a/x86_64/sysdeps.h +++ b/x86_64/sysdeps.h @@ -107,12 +107,12 @@ typedef union x86_64_boot_params { /* 0x06 */ UINT8 orig_video_mode; /* LDR */ /* 0x07 */ UINT8 orig_video_cols; /* LDR */ -/* 0x08 */ UINT16 unused_1; /* unused */ +/* 0x08 */ UINT16 pad_1; /* unused */ /* %%TBD */ /* 0x0A */ UINT16 orig_ega_bx; /* LDR */ -/* 0x0C */ UINT16 unused_2; /* unused */ +/* 0x0C */ UINT16 pad_2; /* unused */ /* Screen height before passing control to kernel. */ /* 0x0E */ UINT8 orig_video_rows; /* LDR */ @@ -174,7 +174,7 @@ typedef union x86_64_boot_params { /* 0x4E */ UINT32 bios_code_len; /* LDR */ /* 0x52 */ UINT16 bios_data_len; /* LDR */ -/* 0x54 */ UINT8 unused_3[0x2C]; /* unused */ +/* 0x54 */ UINT8 pad_3[0x2C]; /* unused */ /* %%TBD */ /* 0x80 */ UINT8 hd0_info[0x10]; /* LDR */ @@ -184,7 +184,7 @@ typedef union x86_64_boot_params { /* 0xA0 */ UINT16 mca_info_len; /* LDR */ /* 0xA2 */ UINT8 mca_info_buf[0x10]; /* LDR */ -/* 0xB2 */ UINT8 unused_4[0x10E]; /* unused */ +/* 0xB2 */ UINT8 pad_4[0x10E]; /* unused */ /* EFI boot loader signature. */ /* 0x1C0 */ UINT8 efi_loader_sig[4]; /* LDR */ @@ -209,9 +209,9 @@ typedef union x86_64_boot_params { /* Available contiguous extended memory in KB. */ /* 0x1E0 */ UINT32 alt_mem_k; /* LDR */ -/* 0x1E4 */ UINT32 unused_51; /* unused */ +/* 0x1E4 */ UINT32 pad_51; /* unused */ /* 0x1E8 */ UINT8 e820_nrmap; -/* 0x1E9 */ UINT32 unused_52[2]; /* unused */ +/* 0x1E9 */ UINT32 pad_52[2]; /* unused */ /* Size of setup code in sectors (1 sector == 512 bytes). */ /* 0x1F1 */ UINT8 setup_sectors; /* BLD */ @@ -220,15 +220,10 @@ typedef union x86_64_boot_params { /* 0x1F2 */ UINT16 mount_root_rdonly; /* BLD */ /* %%TBD */ -/* 0x1F4 */ UINT16 sys_size; /* BLD */ +/* 0x1F4 */ UINT32 sys_size; /* BLD */ /* %%TBD */ -/* 0x1F6 */ UINT16 swap_dev; /* BLD */ - -/* %%TBD */ -/* 0x1F8 */ UINT16 ramdisk_flags; /* BLD */ -#define RAMDISK_PROMPT 0x8000 -#define RAMDISK_LOAD 0x4000 +/* 0x1F8 */ UINT16 ram_size_DNU; /* BLD */ /* %%TBD */ /* 0x1FA */ UINT16 video_mode_flag; /* BLD */ @@ -236,12 +231,8 @@ typedef union x86_64_boot_params { /* %%TBD */ /* 0x1FC */ UINT16 orig_root_dev; /* BLD */ -/* 0x1FE */ UINT8 unused_6; /* unused */ - /* %%TBD */ -/* 0x1FF */ UINT8 aux_dev_info; /* LDR */ -#define NO_MOUSE 0x00 -#define FOUND_MOUSE 0xAA +/* 0x1FE */ UINT16 boot_flag; /* ? */ /* Jump past setup data (not used in EFI). */ /* 0x200 */ UINT16 jump; /* BLD */ @@ -283,16 +274,21 @@ typedef union x86_64_boot_params { /* 0x21C */ UINT32 initrd_size; /* LDR */ /* %%TBD */ -/* 0x220 */ UINT32 bootsect_helper; /* BLD */ +/* 0x220 */ UINT32 bootsect_helper_DNU; /* BLD */ /* %%TBD */ /* 0x224 */ UINT16 heap_end_ptr; /* LDR */ /* %%TBD */ -/* 0x226 */ UINT16 unused_7; /* LDR */ +/* 0x226 */ UINT8 ext_loader_ver; /* LDR */ +/* 0x227 */ UINT8 ext_loader_type; /* LDR */ /* 0x228 */ UINT32 cmdline_addr; /* LDR */ -/* 0x22C */ UINT32 unused_8[41]; +/* 0x22C */ UINT32 initrd_addr_max; /* BLD */ +/* 0x230 */ UINT32 kernel_alignment; /* BLD */ +/* 0x234 */ UINT8 relocatable_kernel; /* BLD */ +/* 0x235 */ UINT8 pad_8[3]; +/* 0x238 */ UINT32 pad_9[38]; /* 0x2D0 */ UINT8 e820_map[2560]; } s; } boot_params_t; @@ -368,6 +364,7 @@ extern UINT8 rmswitch_image[]; extern UINTN rmswitch_size; extern INTN x86_64_use_legacy_free_boot(); +extern INTN x86_64_text_mode(); /* * How to jump to kernel code @@ -382,7 +379,6 @@ start_kernel(VOID *kentry, boot_params_t *bp) UINT16 kernel_cs; } jumpvector; VOID *jump_start; - uint64_t temp; /* * Disable interrupts. @@ -390,22 +386,16 @@ start_kernel(VOID *kentry, boot_params_t *bp) asm volatile ( "cli" : : ); /* - * Relocate kernel (if needed), and initrd (if present). - * Copy kernel first, in case kernel was loaded overlapping where we're - * planning to copy the initrd. This assumes that the initrd didn't - * get loaded overlapping where we're planning to copy the kernel, but - * that's pretty unlikely since we couldn't alloc that space for the - * kernel (or the kernel would already be there). + * Relocate kernel (if needed). + * This assumes that the initrd didn't get loaded overlapping where + * we're planning to copy the kernel, but that's pretty unlikely + * since we couldn't alloc that space for the kernel (or the kernel + * would already be there). */ if (kernel_start != kernel_load_address) { MEMCPY(kernel_start, kernel_load_address, kernel_size); } - if (bp->s.initrd_start) { - temp = bp->s.initrd_start; - MEMCPY(INITRD_START, temp , bp->s.initrd_size); - bp->s.initrd_start = INITRD_START; - } /* * Copy boot sector, setup data and command line * to final resting place. We need to copy @@ -468,7 +458,8 @@ start_kernel(VOID *kentry, boot_params_t *bp) } typedef struct sys_img_options { - UINT8 nothing_yet; + UINT8 dummy; /* forces non-zero offset for first field */ + UINT8 text_mode; /* do not try to initialize Graphics Output Protocol */ } sys_img_options_t; #endif /* __ELILO_SYSDEPS_X86_64_H__ */ diff --git a/x86_64/system.c b/x86_64/system.c index 6874acc..089f1f5 100644 --- a/x86_64/system.c +++ b/x86_64/system.c @@ -38,11 +38,19 @@ */ #include #include +#include #include "elilo.h" #include "loader.h" #include "rmswitch.h" +#define DEBUG_CREATE_BOOT_PARAMS 0 +#if DEBUG_CREATE_BOOT_PARAMS +#define DPR(a) do { if (elilo_opt.debug) { Print a; } } while ( 0 ) +#else +#define DPR(a) +#endif + extern loader_ops_t bzimage_loader, plain_loader, gzip_loader; /* @@ -105,14 +113,16 @@ UINTN high_base_mem = 0x90000; UINTN high_ext_mem = 32 * 1024 * 1024; /* This starting address will hold true for all of the loader types for now */ -VOID *kernel_start = (void *)DEFAULT_KERNEL_START; +VOID *kernel_start = (VOID *)DEFAULT_KERNEL_START; /* The kernel may load elsewhere if EFI firmware reserves kernel_start */ -VOID *kernel_load_address = DEFAULT_KERNEL_START; +VOID *kernel_load_address = (VOID *)DEFAULT_KERNEL_START; VOID *initrd_start = NULL; UINTN initrd_size = 0; +INTN e820_map_overflow = 0; + INTN sysdeps_init(EFI_HANDLE dev) { @@ -131,10 +141,8 @@ sysdeps_init(EFI_HANDLE dev) /* * initrd_get_addr() * Compute a starting address for the initial RAMdisk image. - * For now, this image is placed immediately after the end of - * the kernel memory. Inside the start_kernel() code, the - * RAMdisk image will be relocated to the top of available - * extended memory. + * For now we suggest 'initrd_addr_max' with room for 32MB, + * as image->pgcnt is not initialized yet. */ INTN sysdeps_initrd_get_addr(kdesc_t *kd, memdesc_t *imem) @@ -146,10 +154,12 @@ sysdeps_initrd_get_addr(kdesc_t *kd, memdesc_t *imem) return -1; } - VERB_PRT(3, Print(L"kstart="PTR_FMT" kentry="PTR_FMT" kend="PTR_FMT"\n", - kd->kstart, kd->kentry, kd->kend)); + VERB_PRT(3, Print(L"initrd_addr_max="PTR_FMT" reserve=%d\n", + param_start->s.initrd_addr_max, 32*MB)); - imem->start_addr = kd->kend; + imem->start_addr = (VOID *) + (((UINT64)param_start->s.initrd_addr_max - 32*MB + 1) + & ~EFI_PAGE_MASK); VERB_PRT(3, Print(L"initrd start_addr="PTR_FMT" pgcnt=%d\n", imem->start_addr, imem->pgcnt)); @@ -157,6 +167,48 @@ sysdeps_initrd_get_addr(kdesc_t *kd, memdesc_t *imem) return 0; } + +/* + * checkfix_initrd() + * Check and possibly fix allocation of initrd memory. + */ +VOID * +sysdeps_checkfix_initrd(VOID *start_addr, memdesc_t *imem) +{ + UINTN pgcnt = EFI_SIZE_TO_PAGES(imem->size); + UINT64 initrd_addr_max = (UINT64)param_start->s.initrd_addr_max; + UINT64 ki_max = initrd_addr_max - imem->size + 1; + VOID *ki_max_addr; + + VERB_PRT( 3, Print(L"loadfile: start_addr="PTR_FMT + " ki_max_addr="PTR_FMT"\n", start_addr, (VOID *)ki_max)); + if (ki_max > UINT32_MAX) { + ERR_PRT((L"Force kernel specified initrd_addr_max="PTR_FMT + " below 4GB\n", (VOID *)initrd_addr_max)); + ki_max = UINT32_MAX - imem->size + 1; + } + ki_max_addr = (VOID *)ki_max; + + if ((UINT64)start_addr > ki_max) { + VERB_PRT(1, Print(L"initrd start_addr="PTR_FMT" above " + "limit="PTR_FMT"\n", start_addr, ki_max_addr)); + free(start_addr); + start_addr = NULL; + } + /* so either the initial allocation failed or it's been to high! */ + if (start_addr == NULL) { + start_addr = alloc_pages(pgcnt, EfiLoaderData, + AllocateMaxAddress, ki_max_addr); + } + if ((UINT64)start_addr > ki_max) { + ERR_PRT((L"Failed to allocate %d pages below %dMB", + pgcnt, (param_start->s.initrd_addr_max+1)>>20)); + free(start_addr); + start_addr = NULL; + } + return start_addr; +} + VOID sysdeps_free_boot_params(boot_params_t *bp) { @@ -199,6 +251,10 @@ static INTN get_video_info(boot_params_t * bp) { UINTN size1; UINT8 i; + if (x86_64_text_mode() == 1) { + Print((L"Skip GOP init, force text-mode.\n")); + return -1; + } efi_status = uefi_call_wrapper( BS->LocateHandle, 5, @@ -209,7 +265,19 @@ static INTN get_video_info(boot_params_t * bp) { (VOID **)Gop_handle); if (EFI_ERROR(efi_status) && efi_status != EFI_BUFFER_TOO_SMALL) { - ERR_PRT((L"LocateHandle GopProtocol failed.")); + Print(L"LocateHandle GopProtocol failed.\n"); + Print(L"--Either no graphics head is installed,\n" \ + "--efi console is set to serial, or,\n" \ + "--the EFI firmware version of this machine is\n" \ + "--older than UEFI 2.0. and does not support GOP"); + Print(L"you can SAFELY IGNORE this error. elilo will\n" \ + "default to text-mode.\n Alternatively you can " \ + "now force text mode by setting config variable\n" \ + "text_mode=1 for x86 in elilo.conf or via cmdline.\n\n"); + Print(L"However if this is the last text output you see\n" \ + "ensure that your kernel console command line\n " \ + "variable matches up with the actual efi boot menu\n" \ + "console output settings.\n\n"); return -1; } Gop_handle = alloc(size, 0); @@ -326,10 +394,56 @@ static INTN get_video_info(boot_params_t * bp) { return 0; } +CHAR16 * +StrStr(IN const CHAR16 *h, IN const CHAR16 *n) +{ + const CHAR16 *t = h; + CHAR16 *res; + int len = 0, i; + + len = StrLen((CHAR16 *)n); + while(*t != CHAR_NULL) { + res = StrChr( t, n[0]); + if (!res) return res; + for( i = 1; i < len && res[i] != CHAR_NULL && res[i] == n[i]; i++); + if ( i == len ) return res; + t = res + 1; + if (t > h + CMDLINE_MAXLEN) return (CHAR16 *)0; + } + + return (CHAR16 *)0; +} + +CHAR8 * +StrStr8(IN const CHAR8 *h, IN const CHAR8 *n) +{ + const CHAR8 *t = h; + CHAR8 *res; + int len = 0, i; + + len = strlena((CHAR8 *)n); + while(*t != 0) { + res = strchra( t, n[0]); + if (!res) return res; + for( i = 1; i < len && res[i] != 0 && res[i] == n[i]; i++); + if ( i == len ) return res; + t = res + 1; + if (t > (h + CMDLINE_MAXLEN)) return (CHAR8 *)0; + } + + return (CHAR8 *)0; +} + /* Convert EFI memory map to E820 map for the operating system * This code is based on a Linux kernel patch submitted by Edgar Hucek */ +#if DEBUG_CREATE_BOOT_PARAMS +static int e820_max = 6; +#else +static int e820_max = E820_MAX; +#endif + /* Add a memory region to the e820 map */ static void add_memory_region (struct e820entry *e820_map, int *e820_nr_map, @@ -338,21 +452,56 @@ static void add_memory_region (struct e820entry *e820_map, unsigned int type) { int x = *e820_nr_map; + static unsigned long long estart = 0ULL; + static unsigned long esize = 0L; + static unsigned int etype = -1; + static int merge = 0; - if (x == E820_MAX) { - Print(L"Too many entries in the memory map!\n"); + if (x == 0) + DPR((L"AMR: %3s %4s %16s/%12s/%s\n", + L"idx", L" ", L"start", L"size", L"type")); + + /* merge adjacent regions of same type */ + if ((x > 0) && e820_map[x-1].addr + e820_map[x-1].size == start + && e820_map[x-1].type == type) { + e820_map[x-1].size += size; + estart = e820_map[x-1].addr; + esize = e820_map[x-1].size; + etype = e820_map[x-1].type; + merge++; return; } - - if ((x > 0) && e820_map[x-1].addr + e820_map[x-1].size == start - && e820_map[x-1].type == type) - e820_map[x-1].size += size; - else { + /* fill up to E820_MAX */ + if ( x < e820_max ) { e820_map[x].addr = start; e820_map[x].size = size; e820_map[x].type = type; (*e820_nr_map)++; + if (merge) DPR((L"AMR: %3d ==> %016llx/%012lx/%d (%d)\n", + x-1, estart, esize, etype, merge)); + merge=0; + DPR((L"AMR: %3d add %016llx/%012lx/%d\n", + x, start, size, type)); + return; } + /* different type means another region didn't fit */ + /* or same type, but there's a hole */ + if (etype != type || (estart + esize) != start) { + if (merge) DPR((L"AMR: %3d ===> %016llx/%012lx/%d (%d)\n", + e820_map_overflow, estart, esize, etype, merge)); + merge = 0; + estart = start; + esize = size; + etype = type; + e820_map_overflow++; + DPR((L"AMR: %3d OVER %016llx/%012lx/%d\n", + e820_map_overflow, start, size, type)); + return; + } + /* same type and no hole, merge it */ + estart += esize; + esize += size; + merge++; } void fill_e820map(boot_params_t *bp, mmap_desc_t *mdesc) @@ -431,6 +580,7 @@ void fill_e820map(boot_params_t *bp, mmap_desc_t *mdesc) break; default: /* We should not hit this case */ + DBG_PRT((L"hit default!?")); add_memory_region(e820_map, &e820_nr_map, md->PhysicalStart, md->NumberOfPages << EFI_PAGE_SHIFT, @@ -444,6 +594,8 @@ void fill_e820map(boot_params_t *bp, mmap_desc_t *mdesc) /* * x86_64 specific boot parameters initialization routine + * + * Note: debug and verbose messages have already been turned off! */ INTN sysdeps_create_boot_params( @@ -459,6 +611,12 @@ sysdeps_create_boot_params( UINT8 row, col; UINT8 mode; UINT16 hdr_version; + UINT8 e820_map_overflow_warned = 0; + +#if DEBUG_CREATE_BOOT_PARAMS + elilo_opt.debug=1; + elilo_opt.verbose=5; +#endif DBG_PRT((L"fill_boot_params()\n")); @@ -483,27 +641,17 @@ sysdeps_create_boot_params( */ 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. + * Do NOT clear out unknown memory in boot sector image. + * This breaks boot protocol >= 2.10 (2.6.31). */ - 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_51, sizeof bp->s.unused_51); - ZeroMem(&bp->s.unused_52, sizeof bp->s.unused_52); - bp->s.unused_6 = 0; - bp->s.unused_7 = 0; - ZeroMem(bp->s.unused_8, sizeof bp->s.unused_8); /* * Tell kernel this was loaded by an advanced loader type. @@ -553,19 +701,17 @@ sysdeps_create_boot_params( DBG_PRT((L"initrd->start_addr="PTR_FMT" initrd->pgcnt=%d\n", initrd->start_addr, initrd->pgcnt)); - /* These RAMdisk flags are not needed, just zero them. */ - bp->s.ramdisk_flags = 0; - + /* 'ramdisk_flags' (@0x1F8) is called 'ram_size' in the meantime, */ + /* see Documentation/x86/boot.txt. */ if (initrd->start_addr && initrd->pgcnt) { + if ( (UINT64)initrd->start_addr > UINT32_MAX ) { + ERR_PRT((L"Start of initrd out of reach (>4GB).")); + free_kmem(); + return -1; + } /* %%TBD - This will probably have to be changed. */ bp->s.initrd_start = (UINT32)(UINT64)initrd->start_addr; bp->s.initrd_size = (UINT32)(initrd->size); - /* - * This is the RAMdisk root device for RedHat 2.2.x - * kernels (major 0x01, minor 0x00). - */ - - bp->s.orig_root_dev = 0x0100; } else { bp->s.initrd_start = 0; bp->s.initrd_size = 0; @@ -589,11 +735,6 @@ sysdeps_create_boot_params( bp->s.mca_info_len = 0; ZeroMem(bp->s.mca_info_buf, sizeof bp->s.mca_info_buf); - /* - * Pointing device presence. The kernel will detect this. - */ - bp->s.aux_dev_info = NO_MOUSE; - /* * EFI loader signature */ @@ -602,6 +743,11 @@ sysdeps_create_boot_params( /* * Kernel entry point. */ + if ( (UINT64)kernel_start != (UINT32)(UINT64)kernel_start ) { + ERR_PRT((L"Start of kernel (will be) out of reach (>4GB).")); + free_kmem(); + return -1; + } bp->s.kernel_start = (UINT32)(UINT64)kernel_start; /* @@ -692,11 +838,9 @@ sysdeps_create_boot_params( CHECK_OFFSET(setup_sectors, 0x1F1, L"%xh"); CHECK_OFFSET(mount_root_rdonly, 0x1F2, L"%xh"); CHECK_OFFSET(sys_size, 0x1F4, L"%xh"); - CHECK_OFFSET(swap_dev, 0x1F6, L"%xh"); - CHECK_OFFSET(ramdisk_flags, 0x1F8, L"%xh"); CHECK_OFFSET(video_mode_flag, 0x1FA, L"%xh"); CHECK_OFFSET(orig_root_dev, 0x1FC, L"%xh"); - CHECK_OFFSET(aux_dev_info, 0x1FF, L"%xh"); + CHECK_OFFSET(boot_flag, 0x1FE, L"%xh"); CHECK_OFFSET(jump, 0x200, L"%xh"); CHECK_OFFSET(setup_sig, 0x202, L"'%-4.4a'"); CHECK_OFFSET(hdr_minor, 0x206, L"%xh"); @@ -710,9 +854,9 @@ sysdeps_create_boot_params( CHECK_OFFSET(kernel_start, 0x214, L"%xh"); CHECK_OFFSET(initrd_start, 0x218, L"%xh"); CHECK_OFFSET(initrd_size, 0x21C, L"%xh"); - CHECK_OFFSET(bootsect_helper, 0x220, L"%xh"); CHECK_OFFSET(heap_end_ptr, 0x224, L"%xh"); CHECK_OFFSET(cmdline_addr, 0x228, L"%xh"); + CHECK_OFFSET(e820_map, 0x2D0, L"%xh"); if (test) { ERR_PRT((L"Boot sector and/or setup parameter alignment error.")); @@ -802,6 +946,31 @@ do_memmap: * and update the bootparam accordingly */ fill_e820map(bp, &mdesc); + +#if DEBUG_CREATE_BOOT_PARAMS + if ( e820_map_overflow == 0 ) + e820_map_overflow = -1; /* force second get_memmap()! */ +#endif + if (e820_map_overflow && !e820_map_overflow_warned) { + CHAR8 *aem = (CHAR8 *)"add_efi_memmap"; + e820_map_overflow_warned++; + +#if DEBUG_CREATE_BOOT_PARAMS + elilo_opt.debug=0; + elilo_opt.verbose=0; +#endif + if (e820_map_overflow == -1 || StrStr8(cmdline, aem)) { + /* Print(L"...mapping again, silently!\n"); */ + goto do_memmap; + } + + Print(L"\nCAUTION: EFI memory map has %d more entr%a" + " than E820 map supports.\n" + "To access all memory, '%a' may be necessary.\n\n", + e820_map_overflow, (e820_map_overflow==1)?"y":"ies", + aem); + goto do_memmap; + } return 0; }